将视图中的选择传递给表单
Posted
技术标签:
【中文标题】将视图中的选择传递给表单【英文标题】:Pass choices from views to form 【发布时间】:2016-05-11 22:08:15 【问题描述】:我使用Bannerform
形式通过add_banner
视图(和模板)创建新的Banner
对象。我使用Options
类来确定哪些affiliation
对象以Bannerform
(affiliation
字段)的形式允许。
我正在尝试,但它给了我 ValueError: too many values to unpack (expected 2)
我的代码在 new_affiliation
是 ForeignKey 时有效,但现在我需要更多值。我想我必须在views
中确定“选择”,否则我在第一次迁移时会遇到问题(它似乎从models.py
调用数据库表,但不是从views.py
,所以如果我把Options.objects.get(id=1)
在models.py
上它给出错误,因为表还不存在)。
我的form.py
:
from django import forms
from core.models import Options, Banner, Affiliation #somethings other
class BannerForm(forms.ModelForm):
name = forms.CharField(max_length=32)
affiliation = forms.ChoiceField('choices')
#affiliation = forms.ModelChoiceField('choices') #same error
class Meta:
model = Banner
exclude = (#some fields)
我的models.py
:
from django.db import models
from django.contrib.auth.models import User
from django import forms
class Options(models.Model):
new_affiliation = models.ManyToManyField('Affiliation')
#new_affiliation = models.ForeignKey('Affiliation') #this worked (with some changes in views)
class Affiliation(models.Model):
name = models.CharField(max_length=32, unique=True)
class Banner(models.Model):
name = models.CharField(max_length=32, unique=True)
affiliation = models.ForeignKey(Affiliation)
我的views.py
:
def add_banner(request):
if request.method == 'POST':
#some code here
else:
options = Options.objects.get(id=1)
print(options.new_affiliation.all()) #controll
choices = options.new_affiliation.all()
print(choices) #controll
form = BannerForm(choices, initial=
#some code regarding other fields
)
return render(request, 'core/add_banner.html', 'form': form)
我的add_banner.html
:
<form role="form" id="banner_form" enctype="multipart/form-data "method="post" action="../add_banner/">
% csrf_token %
% for hidden in form.hidden_fields %
hidden
% endfor %
% for field in form.visible_fields %
field.errors
field.label
field
field.help_text
<br />
% endfor %
我们将不胜感激。
已更新。我只改了views.py
:
def add_banner(request):
if request.method == 'POST':
#some code here
else:
options = Options.objects.get(id=1)
print(options.new_affiliation.all()) #controll
choices = tuple(options.new_affiliation.all())
print(choices) #controll
form = BannerForm(choices, initial=
#some code regarding other fields
)
return render(request, 'core/add_banner.html', 'form': form)
但还是报错。
更新 2。如果我直接从 form.py 传递选择,它可以工作:
我的views.py
:
def add_banner(request):
if request.method == 'POST':
#some code here
else:
form = BannerForm(request.POST or None, initial=
#some code regarding other fields
)
return render(request, 'core/add_banner.html', 'form': form)
我的forms.py
:
class BannerForm(forms.ModelForm):
options = Options.objects.get(id=1)
choices = options.new_affiliation.all()
name = forms.CharField(max_length=32)
affiliation = forms.ModelChoiceField(choices)
不幸的是,这给第一次迁移带来了问题(见上文)。
我正在尝试使用一些 init 方法传递选择...
我的forms.py
:
class BannerForm(forms.ModelForm):
name = forms.CharField(max_length=32)
affiliation = forms.ModelChoiceField(choices)
def __init__(self, *args, **kwargs):
options = Options.objects.get(id=1)
choices = options.new_affiliation.all()
#choices = kwargs.pop('choices')
super(RegentForm, self).__init__(*args, **kwargs)
self.fields['affiliation'] = choices
但它说选择是不确定的
【问题讨论】:
【参考方案1】:完成!
我的form.py
:
class BannerForm(forms.ModelForm):
name = forms.CharField(max_length=32, label='Nome')
def __init__(self, *args, **kwargs):
options = Options.objects.get(id=1)
choices = options.new_affiliation.all()
super(BannerForm, self).__init__(*args, **kwargs)
self.fields['affiliation'] = forms.ModelChoiceField(choices)
self.fields['affiliation'].initial = choices
class Meta:
model = Banner
我的views.py
:
def add_banner(request):
if request.method == 'POST':
#some code here
else:
form = BannerForm(request.POST or None, initial=
#some code here
)
return render(request, 'core/add_banner.html', 'form': form)
谢谢
【讨论】:
酷,你成功了。是的,init 方法是一个很好的补充。您需要在渲染之前对信息进行更多处理。看起来不错【参考方案2】:从我在这里看到的情况来看,您似乎收到了“太多值无法解包”的错误,因为您没有将“选择”作为正确的类型发送。 ChoiceField 仅将选择作为元组,如模型的the documentation 中所示。如果您希望基于 QuerySet 定义选择,则必须将其转换为可以解释为有效“选择”的元组。例如,在我的一个项目中,我需要准备一组年份作为元组,以便我可以允许用户从预先确定的年份列表中进行选择。我指定了以下函数来执行此操作:
def years():
response = []
now = datetime.utcnow()
for i in range(1900, now.year + 1):
response.append([i, str(i)])
return tuple(response)
由于元组本来就是不可变的,所以根据原则进行转换通常不是一个好主意。但是,在这种情况下,似乎有必要作为一种措施来声明您可以接受这些陈述的可能变化。
在您的具体情况下,您可以考虑这样做:
choices = tuple(options.new_affiliation.all().values())
我没有测试过这段代码,坦率地说,我对你的项目并不完全熟悉,并且可能在这个回复的某些部分有误。因此,它可能需要进一步调整,但请试一试。根据您的错误,这绝对是程序当前正在中断的地方。如果您取得任何进展,请在此处更新。
【讨论】:
它给出一个错误:AttributeError: 'tuple' object has no attribute 'get'。模板渲染期间出错。错误在 hidden 行。也许可以帮助知道我的选择 = options.new_affiliation.all() 打印的是: [, ], 你的选择 = tuple(options.new_affiliation.all().values())打印的是:('id': 1, 'name': 'Red', 'id': 2, 'name': 'Black')。这里最后一行报错dpaste.com/30AY564 @fabio 您可能希望以不同的格式发送它,以便它在没有任何关键字的情况下可读。你可以这样做:choices = tuple(options.new_affiliation.all().get('name').values()) 这将只检索像 (('Black'), ('Red')) 这样的名称-- 基于这里的sn-ps,确定到底发生了什么仍然有点困难,所以试着多弄点结果,然后回复更多信息。我可以在自己的 IDE 中尝试其中的一些代码,看看它是否会产生理想的结果。 我不知道给你什么信息...我编辑了我的第一篇文章添加了一些东西。也许问题在于它接受像字段这样的选择并尝试在模板上呈现它......也许我们应该在一些 init 方法中传递选择? 这是它应该如何工作的: 1) 在开始时数据库不存在。 2) 我使用第一次迁移创建数据库 3) 我用脚本填充数据库。我创建了一些附属对象。 4) 我创建了一个且只有一个选项对象。在 new_affilation 字段中,我只选择了一些从属对象 5) 用户可以创建一个横幅,在我在 pass4 中为他们选择的那些之间只选择一个从属关系 6) 有时我会修改选项对象以允许在新横幅中使用不同的从属关系。我希望这能澄清以上是关于将视图中的选择传递给表单的主要内容,如果未能解决你的问题,请参考以下文章
从视图中,如何将自定义“选择”传递到表单的 ChoiceField?