0

In one of my recent project, I created a website for users to submit their information in a multi-stage form, in each form I use get_or_create to see if the user submit information previously or not, for example, consider user education model as follows,

class UserEducation(models.Model):
    user = models.ForeignKey(AUTH_USER_MODEL, on_delete=models.CASCADE)
    university_name = models.CharField(max_length=100)

in the view, I have the following code,

def education_view(request):
    if request.method == "POST":
        uedu, created = UserEducation.objects.get_or_create(user=request.user)
        uedu.university_name = request.POST['university_name']
        uedu.save()
        return HttpResponse("success")

I didn't set uploading for the submit button and the problem is some users have multiple education object!

Does anyone know why this happened and whats is wrong with get_or_create?

smrf
  • 349
  • 3
  • 16

3 Answers3

1

Insted you can use update_or_create

uedu, created = UserEducation.objects.update_or_create(
    user=request.user,uedu.university_name = request.POST['university_name'],
    defaults={'user': 'default_value'},
)
  • amazing suggestion, I didn't found any concurrent note or other things about this function, I think this is the best answer – smrf Jul 28 '20 at 05:27
  • However, your answer should be changed because I want to find the education based on the user and then update the university – smrf Jul 28 '20 at 05:31
  • No this does not work body because it search based on university name and create a new one each time – smrf Jul 28 '20 at 05:35
0

I think the reason is that, as every time you moved on to the next step, Django will think that you tell it to create a new object because, as every time you submit a form, a new Model will be created.

What you should do is to halt the process until everything is finished. Something like:

class Person(models.Model):
    fn = models.CharField(max_length=40)

class Pet(models.Model):
    owner = models.ForeignKey(Person)
    name = models.CharField(max_length=40)

class PersonForm(forms.ModelForm):
    class Meta:
        model = Person

class PetForm(forms.ModelForm):
    class Meta:
        model = Pet
        exclude = ('owner',)

#views
def step1(request):
    initial={'fn': request.session.get('fn', None)}
    form = PersonForm(request.POST or None, initial=initial)
    if request.method == 'POST':
        if form.is_valid():
            request.session['fn'] = form.cleaned_data['fn']
            return HttpResponseRedirect(reverse('step2'))
    return render(request, 'step1.html', {'form': form})

def step2(request):
    form = PetForm(request.POST or None)
    if request.method == 'POST':
        if form.is_valid():
            pet = form.save(commit=False)
            person = Person.objects.create(fn=request.session['fn'])
            pet.owner = person
            pet.save()
            return HttpResponseRedirect(reverse('finished'))
    return render(request, 'step2.html', {'form': form})

Reference

crimsonpython24
  • 2,223
  • 2
  • 11
  • 27
  • This seems a reasonable answer, but my approach create person in the first step (login/register) and then in each step store something about it in the database and I didn't use sessions at all, in every step I just update the database – smrf Jul 28 '20 at 04:30
  • Can you try using `update_or_create`? [Documentation](https://docs.djangoproject.com/en/3.0/ref/models/querysets/#update-or-create) – crimsonpython24 Jul 28 '20 at 04:41
  • in the first place I didn't have university name just user and I think if I put university name in kwargs based on the documentation a new instance is created again – smrf Jul 28 '20 at 05:35
0

I find the following note in the documentation,

Warning

This method is atomic assuming that the database enforces uniqueness of the keyword arguments (see unique or unique_together). If the fields used in the keyword arguments do not have a uniqueness constraint, concurrent calls to this method may result in multiple rows with the same parameters being inserted.

the university does not have a unique constraint on the user foreign key and as the result, multiple objects will be saved in the concurrent calls.

smrf
  • 349
  • 3
  • 16