Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django - issue with get_or_create - results in two objects created in DB

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'))
like image 405
Thomas Kremmel Avatar asked Oct 04 '11 18:10

Thomas Kremmel


1 Answers

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....

like image 141
Bernhard Vallant Avatar answered Sep 20 '22 03:09

Bernhard Vallant