Optimize your get_or_create blocks

Tue Sep 15, 2009

Was going through a code review, and saw something like this:

def some_function(user_id, bobj_id):
    user = User.objects.get(id=user_id)
    bobj=Bobj.objects.get(id=bobj_id
    item, created = MyObject.objects.get_or_create(user=user, bobj=bobj)
    return item

But that is two hits to the database we don’t need since the id’s are passed in. Remember, if you have id’s then you can shortcut pulling the object from the ORM like this:

item, created = MyObject.objects.get_or_create(user__id=user_id, bobj__id=bobj_id) That will do the

.get()

just fine, but fails when it tries to

.create()

with this error:

psycopg2.IntegrityError: null value in column “user_id” violates not-null constraint

You got the error because

get_or_create

does not automatically use the query spec for the default. There’s probably an enhancement filed for that. Remember to send in the defaults explicitly:

item, created = MyObject.objects.get_or_create(user__id=user_id, bobj__id=bobj_id,
                defaults={'user_id':user_id, 'bobj_id':bobj_id})

Be sure you look for that in your api calls where you have mainly ids coming in and not object references.