Django:用户的外键 -> 表单未验证,因为需要字段
Django: Foreign Key to User -> Form is not validating because field is required
我目前正在创建一个包含两部分的注册页面
- 一部分是关于用户名和密码。
- 第二部分是关于选择自己的PC-Configuration
定义完所有内容后,用户可以注册以进入主页面。
因此我得到了一个名为 "PC_Configuration" 的模型,其中包含 Processors/Graphicscards 等不同数据库模型的一堆外键。 :
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)
此外,用户有一个 ForeignKey,用于将配置连接到相应的用户 ID。
在 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
但是关于User-ID应该自动分配给配置的事实,这里没有这个字段。
在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 配置,因为表单未验证。
有
print(form.errors)
我一直在努力弄清楚为什么它说
<ul class="errorlist"><li>user<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
所以似乎有必要在检查之前定义“用户”字段,如果表单正在验证并随后在实例中定义用户。
这就是我尝试这样做的原因:
form.user = request.user
但它仍然无法正常工作,我无法弄清楚到底是什么问题,因为“用户”不应该是表单验证的一部分。
你能帮帮我吗?
提前致谢!
像这样的事情会让你的时间更简单...
- 您的
related_name
有点假;从另一个模型的“观点”来看,它们应该是相反的名称。 (此外,您永远不需要在 Django 中手动将 _id
添加到您的字段。)如果您省略 related_names,它们将隐含地成为 pc_configuration_set
.
on_delete=DO_NOTHING
可能不是一个好主意。 PROTECT
是一个很好的默认值。
- 将用户名和密码作为表单中的字段处理会更容易。
- 您缺少
exclude = ["user"]
,因此如果您的模板没有呈现 user
的字段,那么它当然会丢失。但是,您也不希望表单的 POSTer 提交任何旧的用户 ID。
- 使用
FormView
删除了管理表单所需的大部分样板文件。
- 我们正在使用
transaction.atomic()
来确保如果保存 PC 配置失败,用户不会最终保存到数据库中。
- 我们将创建的用户分配给
form.instance
,这是新的但尚未保存的 PC 配置。
(当然,假设这些在不同的文件中。)
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"))
我目前正在创建一个包含两部分的注册页面
- 一部分是关于用户名和密码。
- 第二部分是关于选择自己的PC-Configuration
定义完所有内容后,用户可以注册以进入主页面。
因此我得到了一个名为 "PC_Configuration" 的模型,其中包含 Processors/Graphicscards 等不同数据库模型的一堆外键。 :
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)
此外,用户有一个 ForeignKey,用于将配置连接到相应的用户 ID。
在 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
但是关于User-ID应该自动分配给配置的事实,这里没有这个字段。
在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 配置,因为表单未验证。
有
print(form.errors)
我一直在努力弄清楚为什么它说
<ul class="errorlist"><li>user<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
所以似乎有必要在检查之前定义“用户”字段,如果表单正在验证并随后在实例中定义用户。
这就是我尝试这样做的原因:
form.user = request.user
但它仍然无法正常工作,我无法弄清楚到底是什么问题,因为“用户”不应该是表单验证的一部分。
你能帮帮我吗?
提前致谢!
像这样的事情会让你的时间更简单...
- 您的
related_name
有点假;从另一个模型的“观点”来看,它们应该是相反的名称。 (此外,您永远不需要在 Django 中手动将_id
添加到您的字段。)如果您省略 related_names,它们将隐含地成为pc_configuration_set
. on_delete=DO_NOTHING
可能不是一个好主意。PROTECT
是一个很好的默认值。- 将用户名和密码作为表单中的字段处理会更容易。
- 您缺少
exclude = ["user"]
,因此如果您的模板没有呈现user
的字段,那么它当然会丢失。但是,您也不希望表单的 POSTer 提交任何旧的用户 ID。 - 使用
FormView
删除了管理表单所需的大部分样板文件。 - 我们正在使用
transaction.atomic()
来确保如果保存 PC 配置失败,用户不会最终保存到数据库中。 - 我们将创建的用户分配给
form.instance
,这是新的但尚未保存的 PC 配置。
(当然,假设这些在不同的文件中。)
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"))