通过覆盖 __init__ 动态创建表单时 Django 表单验证失败
Django form validation fails when dynamically creating form by overwriting __init__
我正在用 Django 编写一个预测应用程序。在基本层面上,它从 API 中提取比赛,填充数据库,最后允许用户对尚未进行的比赛进行预测。因为我不知道比赛之前会有多少场比赛,所以我想创建一个表单,可以根据需要动态添加尽可能多的字段。
我目前有一个“工作”版本,但它会进一步产生问题。这是工作版本:(公平警告,这是我的测试,请原谅命名约定)
views.py
def ftest(request, contest_id):
matches_list = Matches.objects.filter(
matches_contest_pk__id = contest_id
).filter(
matches_complete = False
).order_by(
'-matches_start_time'
)
matches = [
f'{match.matches_team_1} vs. {match.matches_team_2}'
for match in matches_list
]
if request.method == 'POST':
form = TestForm(form_fields = matches, data=request.POST)
if form.is_valid():
return HttpResponseRedirect('/thanks/')
else:
print(form.errors)
else:
form = TestForm(form_fields = matches)
context = {
'form': form,
}
return render(request, 'predictions/test.html', context)
forms.py
from django import forms
from .models import Matches
class TestForm(forms.Form):
def __init__(self, *args, **kwargs):
form_fields = kwargs.pop('form_fields', None)
super(TestForm, self).__init__(*args, **kwargs)
for field in form_fields:
self.fields[field] = forms.CharField(label = f'{field}', max_length = 100)
正如我所说,这可行,但理想情况下,我希望将每个字段的 ID 设置为数据库中的实际 ID。我对此的解决方案是更改视图以通过 form_fields
发送字典列表并更新表单以使用它。这就是它的样子:
views.py
def ftest(request, contest_id):
matches_list = Matches.objects.filter(
matches_contest_pk__id = contest_id
).filter(
matches_complete = False
).order_by(
'-matches_start_time'
)
matches = [
{ 'label': f'{match.matches_team_1} vs. {match.matches_team_2}', 'id': match.id, }
for match in matches_list
]
if request.method == 'POST':
form = TestForm(form_fields = matches, data=request.POST)
if form.is_valid():
return HttpResponseRedirect('/thanks/')
else:
print(form.errors)
else:
form = TestForm(form_fields = matches)
context = {
'form': form,
}
return render(request, 'predictions/test.html', context)
forms.py
from django import forms
from .models import Matches
class TestForm(forms.Form):
def __init__(self, *args, **kwargs):
form_fields = kwargs.pop('form_fields', None)
super(TestForm, self).__init__(*args, **kwargs)
for field in form_fields:
self.fields[field['id']] = forms.CharField(label = field['label'], max_length = 100)
但是,进行此更改后,表单未通过验证。它只是为每个字段抛出一个 This field is required.
错误。理想情况下,我希望用户返回到同一页面,并在字段中填写他们的预测。关于如何解决这个问题的任何建议?我是从错误的角度处理问题还是误解了表单在 Django 中的工作方式?
已解决。
问题出在我发送到表单创建方法的内容上。当我创建字典时,它是这样完成的:
matches = [
{ 'label': f'{match.matches_team_1} vs. {match.matches_team_2}', 'id': match.id, }
for match in matches_list
]
原来问题出在 'id' 键上。我给它分配了一个整数,它在表单创建中需要是一个字符串。所以解决方案看起来像:
matches = [
{ 'label': f'{match.matches_team_1} vs. {match.matches_team_2}', 'id': str(match.id), }
for match in matches_list
]
我正在用 Django 编写一个预测应用程序。在基本层面上,它从 API 中提取比赛,填充数据库,最后允许用户对尚未进行的比赛进行预测。因为我不知道比赛之前会有多少场比赛,所以我想创建一个表单,可以根据需要动态添加尽可能多的字段。
我目前有一个“工作”版本,但它会进一步产生问题。这是工作版本:(公平警告,这是我的测试,请原谅命名约定)
views.py
def ftest(request, contest_id):
matches_list = Matches.objects.filter(
matches_contest_pk__id = contest_id
).filter(
matches_complete = False
).order_by(
'-matches_start_time'
)
matches = [
f'{match.matches_team_1} vs. {match.matches_team_2}'
for match in matches_list
]
if request.method == 'POST':
form = TestForm(form_fields = matches, data=request.POST)
if form.is_valid():
return HttpResponseRedirect('/thanks/')
else:
print(form.errors)
else:
form = TestForm(form_fields = matches)
context = {
'form': form,
}
return render(request, 'predictions/test.html', context)
forms.py
from django import forms
from .models import Matches
class TestForm(forms.Form):
def __init__(self, *args, **kwargs):
form_fields = kwargs.pop('form_fields', None)
super(TestForm, self).__init__(*args, **kwargs)
for field in form_fields:
self.fields[field] = forms.CharField(label = f'{field}', max_length = 100)
正如我所说,这可行,但理想情况下,我希望将每个字段的 ID 设置为数据库中的实际 ID。我对此的解决方案是更改视图以通过 form_fields
发送字典列表并更新表单以使用它。这就是它的样子:
views.py
def ftest(request, contest_id):
matches_list = Matches.objects.filter(
matches_contest_pk__id = contest_id
).filter(
matches_complete = False
).order_by(
'-matches_start_time'
)
matches = [
{ 'label': f'{match.matches_team_1} vs. {match.matches_team_2}', 'id': match.id, }
for match in matches_list
]
if request.method == 'POST':
form = TestForm(form_fields = matches, data=request.POST)
if form.is_valid():
return HttpResponseRedirect('/thanks/')
else:
print(form.errors)
else:
form = TestForm(form_fields = matches)
context = {
'form': form,
}
return render(request, 'predictions/test.html', context)
forms.py
from django import forms
from .models import Matches
class TestForm(forms.Form):
def __init__(self, *args, **kwargs):
form_fields = kwargs.pop('form_fields', None)
super(TestForm, self).__init__(*args, **kwargs)
for field in form_fields:
self.fields[field['id']] = forms.CharField(label = field['label'], max_length = 100)
但是,进行此更改后,表单未通过验证。它只是为每个字段抛出一个 This field is required.
错误。理想情况下,我希望用户返回到同一页面,并在字段中填写他们的预测。关于如何解决这个问题的任何建议?我是从错误的角度处理问题还是误解了表单在 Django 中的工作方式?
已解决。
问题出在我发送到表单创建方法的内容上。当我创建字典时,它是这样完成的:
matches = [
{ 'label': f'{match.matches_team_1} vs. {match.matches_team_2}', 'id': match.id, }
for match in matches_list
]
原来问题出在 'id' 键上。我给它分配了一个整数,它在表单创建中需要是一个字符串。所以解决方案看起来像:
matches = [
{ 'label': f'{match.matches_team_1} vs. {match.matches_team_2}', 'id': str(match.id), }
for match in matches_list
]