Open kgilpin opened 3 months ago
Resolve UNIQUE constraint violation when creating a voucher with a previously deleted voucher's name
There is an IntegrityError
when trying to create a voucher with the same name as a previously deleted voucher. This error occurs because the offer_conditionaloffer
table has a unique constraint on the name
field. When a voucher is deleted, the corresponding offer is not deleted, causing subsequent attempts to create a voucher with the same name to fail.
The error arises due to the unique constraint on the name
field of the offer_conditionaloffer
table. When a voucher is deleted, the associated offer should also be deleted. However, this does not currently happen, leading to the unique constraint being violated on subsequent voucher creations with the same name. To resolve this issue, we need to ensure that the offer associated with the voucher is also deleted when the voucher is deleted.
We should implement the following:
post_delete
signal to delete the associated offer when a voucher is deleted.src/oscar/apps/voucher/migrations/0009_make_voucher_names_unique.py
: Modify this migration script to ensure that all existing voucher names are unique.
src/oscar/apps/dashboard/vouchers/views.py
:
VoucherDeleteView
to ensure that associated offers are deleted when the voucher is deleted.post_delete
signal to automate the deletion of related offers.src/oscar/apps/voucher/models.py
:
post_delete
signal handler to delete associated offers when a voucher is deleted.Detailed Steps:
Migration Script:
VoucherDeleteView
Changes:
from django.db.models.signals import post_delete
from django.dispatch import receiver
from oscar.apps.voucher.models import Voucher
@receiver(post_delete, sender=Voucher)
def delete_associated_offers(sender, instance, **kwargs):
offers = ConditionalOffer.objects.filter(name=instance.name, offer_type=ConditionalOffer.VOUCHER)
for offer in offers:
if offer.vouchers.count() == 1 and offer.vouchers.first() == instance:
offer.delete()
Signal Handler:
from django.db.models.signals import post_delete
from django.dispatch import receiver
from oscar.apps.offer.models import ConditionalOffer
@receiver(post_delete, sender=Voucher)
def delete_associated_offers(sender, instance, **kwargs):
offers = ConditionalOffer.objects.filter(name=instance.name, offer_type=ConditionalOffer.VOUCHER)
for offer in offers:
if offer.vouchers.count() == 1 and offer.vouchers.first() == instance:
offer.delete()
Ensure the new migration script is applied to the database:
python manage.py migrate
By implementing these changes, deleting a voucher will also delete the associated offer, resolving the issue where recreating vouchers with previously used names caused an IntegrityError.
Error if create voucher name matching to voucher name deleted
Server time: Thu, 9 Jan 2020 02:36:46 +0000
Got error 500 when create voucher
Steps to Reproduce
Create new voucher Delete that voucher Create voucher again with same voucher name deleted
Suggestions
Oscar's models do not prevent the same offer being used in multiple places - so indiscriminately deleting all offers could affect other vouchers or remove an offer that is used for another purpose.
We should check that :
I also think this should be done in a post_delete signal so that there is no risk of integrity errors if the delete fails for another reason.