I´ve got a "single" method within a web api that makes two database calls
- Ensure with count() an specific objects does not exists
- Save the object if it doesn´t exists already
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):
- Call 1 => count() == 0
- Call 2 => count() == 0 (it´s 0 because the first call didn´t finish processing and saving the object at this moment)
- Call 1 => saves the object
- Call 2 => saves the object because count() == 0
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?