Reputation: 151
I'm currently creating a Registration-Page with two parts
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.:
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!
Upvotes: 0
Views: 743
Reputation: 168957
You'll have a simpler time with something like this...
related_name
s 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.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.FormView
removes most of the boilerplate required to manage forms.transaction.atomic()
to make sure the user doesn't get finally saved to the database if saving the PC Configuration fails.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"))
Upvotes: 2