how to catch A 'UNIQUE constraint failed' 404 in django

Question:

How do I specifically catch a UNIQUE constraint failed 404 in the following code, I know I have to add something in the ( here? ) section

try:
    q = AnswerModel(user=user, yes_question=question_model)
    q.save()
except ( here? ):
    return HttpResponseRedirect('/user/already_exists')
Asked By: Sprig Mendle

||

Answers:

from django.db import IntegrityError

except IntegrityError:

This is what you need.

EDITED for @mbrochh:

from django.db import IntegrityError

except IntegrityError as e: 
    if 'unique constraint' in e.message: # or e.args[0] from Django 1.10
        #do something

Yes, you can be more precise but in question case UNIQUE failed is highly likely.

Answered By: torm

Usually the “ask for forgiveness” principle is a good practice in programming but in this special case, I would not recommend it.

The exception you are looking for is IntegrityError. You could have easily figured that out yourself by simply removing the try-catch block and forcing that exception. The traceback shows the exception class.

The problem is, there are several different kinds of integrity errors, so inside your try-catch block you would have to check for something like if ex.pgcode == 23505 to see if this is actually a UNIQUE constraint error. This has been answered before here: IntegrityError: distinguish between unique constraint and not null violations

It gets worse: Each ORM has different error codes, the field name will not be pgcode but something else and some ORMs don’t throw UNIQUE constraints at all. So if you are building a reusable app or if you are using a ORM that sucks (such as MySQL) or if you are not sure if you will change the database of your project at some time in the future, you should not do this!

The better way is simply removing the try-catch block and check if the object is already in the database before saving.

I don’t know which field is UNIQUE in your case, so I will just assume that it is the user field. Your code would look something like this:

answers = AnswerModel.objects.filter(user=user)
if answers:
   return HttpResponseRedirect('/user/already_exists')
obj = AnswerModel.objects.create(user=user, yes_question=question_model)
...

If you are dealing with a combined unique constraint, the first line would be this:

answers = AnswerModel.objects.filter(user=user, yes_question=question_model)
Answered By: mbrochh

IMHO, I would recommend to resolve this situation by get_or_create().

new_obj, created = AnswerModel.objects.get_or_create(user=user, yes_question=question_model)
if created:
    do_something_for_new_object(new_obj)
else:
    logging.error("Duplicated item.")
    return
Answered By: Walter Liu

Unique constraint fail return :”(‘UNIQUE constraint failed: notepad_notepadform.title’)” which is basically a tuple,So we can use below code to catch it and do whatever required:

from django.db import IntegrityError
try:
        if form.is_valid():
            form.save()

    except IntegrityError as e:
        if 'UNIQUE constraint' in str(e.args):
            #your code here
Answered By: nofoobar

For Python > 3.5

You need:

except IntegrityError as e: 
                if 'unique constraint' in e.args:

Example:

from django.db import IntegrityError

 for column in csv.reader(io_string, delimiter=',', quotechar="|"):
     try:
         _, created = Brand.objects.update_or_create(
            system_id=column[0],
            name=column[1],
            slug=column[2],
            description=column[3],
            image=column[4]
           )
     except IntegrityError as e: 
           if 'unique constraint' in e.args:
               continue 
Answered By: Omar Gonzales

Found in django.db.models.query.QuerySet._create_object_from_params. And with some change:

from typing import Any, Dict, Type  
from django.db import transaction, IntegrityError, Model


def get_or_create_obj(model: Type[Model], defaults: Dict[str, Any] = None, **kwargs: Any):
    defaults = defaults or {}
    try:
        with transaction.atomic():
            return model.objects.create(**kwargs, **defaults), True
    except IntegrityError as e:
        try:
            return model.objects.using("default").get(**kwargs), False
        except model.DoesNotExist:
            pass
        raise e
Answered By: Evgeni Shudzel
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.