1

I´ve got a "single" method within a web api that makes two database calls

  1. Ensure with count() an specific objects does not exists
  2. 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):

  1. Call 1 => count() == 0
  2. Call 2 => count() == 0 (it´s 0 because the first call didn´t finish processing and saving the object at this moment)
  3. Call 1 => saves the object
  4. 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?

6
  • How do you tell the object exists already? Commented Aug 15, 2015 at 16:52
  • Hi @spectras I edited the question with a code sample Commented Aug 15, 2015 at 16:56
  • So, basically, you know that "this is the same object" because follow.influencer and follow.follower are the same. Then yeah, that means they are unique together. Commented Aug 15, 2015 at 16:59
  • exactly, just by checking those two properties. So you think that unique_together is the right solution? Commented Aug 15, 2015 at 17:01
  • That's its very purpose, yes. Commented Aug 15, 2015 at 17:01

1 Answer 1

1

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!
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.