McAbra
McAbra

Reputation: 2524

Django concurrent get_or_create

I'm concerned about one thing.
Using Django 1.7 (MySQL in the most default installation) I'm making a POST to a Django REST Framework APIView. Over there I'm doing a:

try:
    MyModel.objects.get(**some_kwargs)
except MyModel.DoesNotExist:
    MyModel.objects.custom_create(**some_kwargs)  # This also creates relative models

Now what will happen if I'll do plenty of concurrent requests?
As I guess you expect I want only the first concurrent request to create an object and any other should get the created one.

Am I ready to go thanks do Django? Have to study about isolation, transactions, atomicity? Or is it more about locking the table? How to (unit) test it?

Please guide me.

Upvotes: 4

Views: 2490

Answers (1)

knbk
knbk

Reputation: 53719

This is not enough to avoid race conditions, as another request can create the model you intended to retrieve between get() and custom_create(). If uniqueness is enforced on a database level, your custom_create() method can fail with an IntegrityError. If it is not, your method is fine, but you cannot prevent duplicate entries due to race conditions.

Django provides the get_or_create() function. This safeguards against race conditions if uniqueness is enforced by your database. It uses the create() method, however, not your custom_create() method, so you'll have to override it if it is acceptable. Otherwise, you can checkout out the source code for get_or_create() and implement it yourself with your custom create method.

The core assumption of get_or_create is that uniqueness is enforced on a database level. Due to this enforcement, create fails if a race condition occurs, and get_or_create can fall back to fetching the object created during the race condition. If this enforcement is missing, the create doesn't fail during a race condition, and a duplicate entry (with a different PK) will be created.

Upvotes: 8

Related Questions