Django: Внешний ключ к пользователю -> Форма не проверяется, поскольку поле является обязательным для заполнения

В настоящее время я создаю регистрационную страницу, состоящую из двух частей

  • Одна часть посвящена имени пользователя и паролю
  • .
  • Вторая часть посвящена выбору собственной конфигурации ПК
  • .

После определения всего, пользователь может зарегистрироваться, чтобы попасть на главную страницу.

Поэтому я получил модель под названием "PC_Configuration" с кучей иностранных ключей к различным моделям баз данных процессоров/графических карт и т.д.:

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)

Кроме того, существует один внешний ключ к User для связи конфигурации с соответствующим идентификатором пользователя.

Внутри views.py я создал DropdownForm для всех выпадающих полей, которые пользователь должен выбрать самостоятельно:

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

Но что касается того, что идентификатор пользователя должен быть присвоен конфигурации автоматически, здесь нет поля для этого.

Определяется в register_view(request) - Метод:

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

И здесь, я полагаю, у нас возникла проблема. При тестировании регистрации тестовые учетные записи продолжают создаваться и успешно входить в систему. Но проблема в том, что не создается PC-Configuration, потому что форма не проходит валидацию.

With

print(form.errors)

Я пытался выяснить, почему именно так, а там было написано

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

Похоже, что необходимо определить "user"-поле до проверки, если форма валидируется и определить пользователя внутри экземпляра после этого.

Вот почему я пытался сделать это:

   form.user = request.user

Но это все еще не работает, и я не могу понять, в чем именно проблема, поскольку "user" не должен быть частью формы-валидации.

Можешь мне помочь?

Заранее благодарю!

Вам будет проще с чем-то подобным...

  • Ваши related_name были несколько ошибочными; они должны быть обратными именами с "точки зрения" другой модели. (Кроме того, в Django никогда не нужно добавлять _id к полям вручную). Если вы уберете related_names, они неявно будут pc_configuration_set.
  • on_delete=DO_NOTHING, скорее всего, не очень хорошая идея. PROTECT является хорошим вариантом по умолчанию.
  • Проще просто обрабатывать имя пользователя и пароль как поля в форме.
  • Вы пропустили exclude = ["user"], поэтому если ваш шаблон не отобразил поле для user, то, конечно, оно будет отсутствовать. Однако, вы также не хотите, чтобы POSTer формы отправлял любой старый id пользователя.
  • Использование FormView удаляет большую часть шаблонов, необходимых для управления формами.
  • Мы используем transaction.atomic() для того, чтобы убедиться, что пользователь не будет окончательно сохранен в базе данных, если сохранение конфигурации ПК не удалось.
  • Мы назначаем созданного пользователя на form.instance, который является новой, но пока еще несохраненной конфигурацией ПК.

(Конечно, представьте, что они находятся в отдельных файлах.)

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"))
Вернуться на верх