I have a simple model:
class InvitationRequest(models.Model):
email = models.EmailField(max_length=255, unique=True)
<
The standard way is to NOT handle this, as:
If, for some reason, you have to be sure that the problem won't happen, you are on your own.
I haven't analyzed the sequence of events in detail but I think that using the SERIALIZABLE isolation level won't really help, it will only cause IntegrityError
(or DatabaseError
) to be raised in a different place.
Overriding Model._perform_unique_checks
sounds to me like a bad idea, you better stay away from monkey patching if possible (and here it is possible).
As for using the table lock to prevent unlikely errors... Well, I'm not a big fan so I cannot recommend that either.
Here's a nice answer to a similar question: https://stackoverflow.com/a/3523439/176186 - I concur that catching IntegrityError
and retrying is probably the easiest sane way to deal with the problem.
EDIT: I found this: Symfony2 - how to recover from unique constraint error after form submission? and I agree with @pid's answer.
I agree with Tomasz Zielinski that common practice is to not worry about this. For most use cases it's just not worth the trouble.
If it is important, the best way is probably with optimistic concurrency. In this case it might look like (untested):
from django.forms.util import ErrorList
def handle_form(request)
form = InvitationRequestForm(request.POST)
try:
if form.is_valid():
form.save()
return HttpResponseRedirect(...) # redirect to success url
except IntegrityError:
form._errors['email'] = ErrorList()
form._errors['email'].append('Error msg')
return render(...) # re-render the form with errors
SERIALIZABLE
won't really help here. As the PostgreSQL documentation makes clear, you have to be prepared to handle serialization failures, which means that the code would look pretty much the same as above. (It would help, though, if you didn't have the unique
constraint forcing the database to throw an exception.)