6

I have a table in my postgresql db holding a state of an hour record. For each month, project and user I need exactly one state. I'm using the get_or_create method to either create a "state" or to retrieve it if it already exists.

HourRecordState.objects.get_or_create(user=request.user, project=project, month=month, year=year, defaults={'state': 0, 'modified_by': request.user})

After running this for about two years without problems I stumbled over the problem that I have one HourRecordState twice in my database. Now each time the get_or_create method is called it throws the following error:

MultipleObjectsReturned: get() returned more than one HourRecordState -- it returned 2

I'm wondering how it could happen that I have two identical records in my DB. Interestingly they have been created at the same time (seconds, not checked the milliseconds).

I checked my code and I have in the whole project only one get_or_create method to create this object. No other create methods in the code.

Would be great to get a hint..

Update:

The objects have been created at almost the same time: First object: 2011-10-04 11:04:35.491114+02 Second object: 2011-10-04 11:04:35.540002+02

And the code:

    try:
        project_id_param = int(project_id_param)
        project = get_object_or_404(Project.objects, pk=project_id_param)

        #check activity status of project
        try:
            is_active_param = project.projectclassification.is_active
        except:
            is_active_param = 0
        if is_active_param == True:
            is_active_param = 1
        else:
            is_active_param = 0
        #show the jqgrid table and the hour record state form
        sub_show_hr_flag = True
        if project is not None:
            hour_record_state, created = HourRecordState.objects.get_or_create(user=request.user, project=project, month=month, year=year, defaults={'state': 0, 'modified_by': request.user})
            state = hour_record_state.state
            manage_hour_record_state_form = ManageHourRecordsStateForm(instance=hour_record_state)

            if not project_id_param is False:
                work_place_query= ProjectWorkPlace.objects.filter(project=project_id_param, is_active=True)
            else:
                work_place_query = ProjectWorkPlace.objects.none()
            work_place_dropdown = JQGridDropdownSerializer().get_dropdown_value_list_workplace(work_place_query)
    except Exception, e:
        project_id_param = False
        project = None
        request.user.message_set.create(message='Chosen project could not be found.')
        return HttpResponseRedirect(reverse('my_projects'))
8
  • 1
    1. How old is the object (has the code changed in the meanwhile)? 2. Do you know that it is impossible to duplicate that object? 3. Is there a problem deleting it? 4. Why don't you have a unique index to prevent that? Commented Oct 4, 2011 at 18:43
  • 1.The object is just a few hours old. Code has not changed in the meanwhile. 2. Yes, I know. 3. No, I will delete it which will solve the issue, but I want to understand how that could happen. 4. Good question. Will add a unique_constraint at db level. 5. See the timestamp it has been created. quite closely together.. hmmm!? Commented Oct 4, 2011 at 18:49
  • no one can answer this without looking at the code. my wild guess is that the code that creates the object for the first time got executed concurrently by multiple processes or threads. basically you need some sort of mutual exclusion, and the UNIQUE constraint might be a good solution as the previous comment says. Commented Oct 4, 2011 at 18:57
  • I added the code block. I added the unique constraint in my DB. thus I should not have this problem again. nevertheless it is strange that the code block is executed twice (hopping over the get_or_create limitation somehow), and within such a short time period. Commented Oct 4, 2011 at 19:29
  • Guess if project is not None will always be True if you use get_object_or_404 before :) Commented Oct 4, 2011 at 19:41

1 Answer 1

9

Well this is not an exact answer to your question, but I think you should change your database scheme and switch to using UNIQUE constraints that help you to maintain data integrity, as the uniqueness will be enforced on database level.

If you state that for every month, user and project you need exactly one state, your model should look something like this (using the unique_together constraint):

class HourRecordState(models.Model):
    user = models.ForeignKey(User)
    project = models.ForeignKey(Project)
    month = models.IntegerField()
    year = models.IntegerField()
    # other fields...

    class Meta:
        unique_together = ((user, project, month, year),)

Because get_or_create is handled by django as a get and create multiple processes seem to be able under certain condition to create the same object twice, but if you use unique_together an exception will be thrown if the attempt is made....

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.