I´ve got a "single" method within a web api that makes two database calls
The logic here is obviously not saving an object if it exists already. Pretty simple. Problem comes when duplicated objects begins to appear in the db table. Then I realized I can´t control bad client calls (duplicated calls at the same time).
So the problem occurs when a second call to this method happen exactly between code blocks 1) and 2) with the same parameters (same object):
Wrong result => my table has two rows with the same values
So I need to not process "Call 2" until "Call 1" code block finishes.
I´ve been researching about this a lot. An option would be blocking the table I´m querying until the method finished execution (but this can bring new problems to the equation).
Other people is talking about using atomic transactions but I don´t see how that can help if another call runs at the same time.
Another possible solution would be using unique_together so it´s impossible to create two rows with same values (I´m starting to think this will be the best option)
I´m lost in the middle of nowhere trying to figure out how to fix this. Given that this issue is hard to test I thought about asking here first. Maybe I´m just missing something obviously simple...
Just to clarify, this is how I tell if an object exists already:
# return error if the follow is already done
current_follow_query = request.user.follows.filter(influencer=influencer)
if current_follow_query.count() > 0:
return Response(status=status.HTTP_204_NO_CONTENT)
# save the actual follow object
obj = Follow(follower=request.user, influencer=influencer)
obj.save()
Any ideas?
So, as you define identity by the two fields influencer
and follower
, then those must be unique. Just tell that to the database, using a unique_together = [('influencer', 'follower')]
constraint.
Now for saving, you will want to rely on the database to perform this test: simply save all the time and handle the errors when they occur.
from django.db import IntegrityError
try:
obj = Follow.objects.create(follower=request.user, influencer=influencer)
except IntegrityError:
# the object already existed!
else:
# the object was successfully created!