Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Django: Foreign Key to User -> Form is not validating because field is required

I’m currently creating a Registration-Page with two parts

  • One part is about the Username and a Passwort.
  • The second part is about choosing the own PC-Configuration

After defining everything, the User can register to get to the Main-Page.

Therefore I got a Model called "PC_Configuration" with a bunch of Foreign-Keys to the different Database-Models of the Processors/Graphicscards etc.:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

class PC_Configuration(models.Model):

user = models.ForeignKey(User, related_name='user_id', on_delete=models.DO_NOTHING)
processor = models.ForeignKey(Processors, related_name='processor_id', on_delete=models.DO_NOTHING)
graphicscard = models.ForeignKey(Graphicscard, related_name='graphicscard_id', on_delete=models.DO_NOTHING)
os = models.ForeignKey(OS, related_name='os_id', on_delete=models.DO_NOTHING)
ram = models.ForeignKey(RAM, related_name='ram_id', on_delete=models.DO_NOTHING)
harddrive = models.ForeignKey(Harddrive, related_name='harddrive_id', on_delete=models.DO_NOTHING)

Also, there is one ForeignKey to the User to connect the Configuration to the respective User-ID.

Inside views.py, I’ve been creating a DropdownForm for all the Dropdown-Fields which the User shall choose on his own:

class DropdownForm(forms.ModelForm):
class Meta:
    model = models.PC_Configuration
    exclude = []

    def __init__(self, *args, **kwargs):
        super(DropdownForm, self).__init__(*args, **kwargs)
        self.fields['processors'].queryset = DropdownForm.objects.all()
        self.fields['processors'].label_from_instance = lambda obj: "%s" % obj.name

        self.fields['graphicscard'].queryset = DropdownForm.objects.all()
        self.fields['graphicscard'].label_from_instance = lambda obj: "%s" % obj.name

        self.fields['os'].queryset = DropdownForm.objects.all()
        self.fields['os'].label_from_instance = lambda obj: "%s" % obj.name

        self.fields['ram'].queryset = DropdownForm.objects.all()
        self.fields['ram'].label_from_instance = lambda obj: "%s" % obj.name

        self.fields['harddrive'].queryset = DropdownForm.objects.all()
        self.fields['harddrive'].label_from_instance = lambda obj: "%s" % obj.name

But regarding the fact, that the User-ID shall be assigned to the Configuration automatically, there’s no field for that in here.

It is defined in the register_view(request) – Method:

def register_view(request):
form = DropdownForm()

if request.method == "POST":
    form = DropdownForm(request.POST)
    username = request.POST.get('username')
    password = request.POST.get('password')

    myuser = User.objects.create_user(username, None, password)
    myuser.save()
    auth.login(request, myuser)

    #form.user = request.user

    print(form.errors)
    if form.is_valid():
        instance = form.save(commit=False)
        instance.user = request.user
        instance.save()
        messages.success(request, "Account has been created successfully")

        return redirect(reverse('gamesearch_view'))

    else:
        print('Failed')
        form = DropdownForm()
        render(request, 'register.html', dict(form=form))

return render(request, 'register.html', dict(form=form))

And in here, we got the problem, I guess.
While Testing the Registration, the Testaccounts keep creating and login successfully. But the problem is, that there’s no PC-Configuration created because the form is not validating.

With

print(form.errors)

I’ve been trying to figure out why exactly and it said

<ul class="errorlist"><li>user<ul class="errorlist"><li>This field is required.</li></ul></li></ul>

So it seems like it’s necessary to define the "user"-field before checking, if the form is validating and defining the user inside an instance afterwards.

That’s why I was trying to do this:

   form.user = request.user

But it’s still not working and I can’t figure out, what’s exactly the problem since "user" shouldn’t be part of the form-validation.

Can you help me out here?

Thank you in Advance!

>Solution :

You’ll have a simpler time with something like this…

  • Your related_names were somewhat bogus; they’re supposed to be the reverse name from the "viewpoint" of the other model. (Also, you never need to add _id to your fields by hand in Django.) If you elide the related_names, they’ll implicitly be pc_configuration_set.
  • on_delete=DO_NOTHING is likely not a good idea. PROTECT is a good default.
  • It’s easier to just handle the username and password as fields in the form.
  • You were missing exclude = ["user"], so if your template didn’t render a field for user, of course it’d be missing. However, you also don’t want the POSTer of the form to submit any old user id.
  • Using a FormView removes most of the boilerplate required to manage forms.
  • We’re using transaction.atomic() to make sure the user doesn’t get finally saved to the database if saving the PC Configuration fails.
  • We assign the created user to form.instance, which is the new but as-of-yet unsaved PC Configuration.

(Of course, imagine these are in separate files.)

from django import forms
from django.db import models, transaction
from django.views.generic import FormView


class PC_Configuration(models.Model):
    user = models.ForeignKey(User, on_delete=models.PROTECT)
    processor = models.ForeignKey(Processors, on_delete=models.PROTECT)
    graphicscard = models.ForeignKey(Graphicscard, on_delete=models.PROTECT)
    os = models.ForeignKey(OS, on_delete=models.PROTECT)
    ram = models.ForeignKey(RAM, on_delete=models.PROTECT)
    harddrive = models.ForeignKey(Harddrive, on_delete=models.PROTECT)


class RegisterAndConfigurePCForm(forms.ModelForm):
    username = forms.CharField(required=True)
    password = forms.CharField(required=True, widget=forms.PasswordInput())

    class Meta:
        model = PC_Configuration
        exclude = ["user"]  # we'll assign this by hand


class RegisterAndConfigureView(FormView):
    form_class = RegisterAndConfigurePCForm
    template_name = "register.html"

    def form_valid(self, form):
        with transaction.atomic():
            user = User.objects.create_user(form.cleaned_data["username"], None, form.cleaned_data["password"])
            form.instance.user = user  # assign user to the to-be-created PC configuration
            form.save()
        return redirect(reverse("gamesearch_view"))
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading