我试图通过继承MultiWidgets和MultiValueFields来了解如何创建表单。 我有一个简单的地址模型和相关的表单:
class Address(models.Model):
user = models.ForeignKey(User)
city = models.CharField(max_length=255)
state = models.CharField(choices = settings.STATES, max_length=50)
postal = models.CharField(max_length=10)
address = models.TextField()
class Meta:
verbose_name_plural = 'Addresses'
class AddressFieldWidget(forms.MultiWidget):
def decompress(self,value):
if value:
return [value[0],value[1],value[2]]
return ''
def format_output(self, rendered_widgets):
str = ''
line_1 = '<td class="align_left"><label for="contact_phone">Address Line 1</label></td>'
for field in rendered_widgets:
str += '<tr>' + line_1
str += '<td class="align_right">%s</td></tr>' % field
return '<tr>' + str + '</tr>'
def value_from_datadict(self,data,files,name):
line_list = [widget.value_from_datadict(data,files,name+'_%s' %i) for i,widget in enumerate(self.widgets)]
try:
return line_list[0] + ' ' + line_list[1] + ' ' + line_list[2]
except:
return ''
class AddressField(forms.MultiValueField):
def __init__(self,*args,**kwargs):
fields = (
forms.CharField(widget=forms.TextInput(attrs={'class':'big'})),
forms.CharField(widget=forms.TextInput(attrs={'class':'big'})),
forms.CharField(widget=forms.TextInput(attrs={'class':'big'})),
)
super(AddressField,self).__init__(*args,**kwargs)
self.widget = AddressFieldWidget(widgets=[fields[0].widget, fields[1].widget, fields[2].widget])
def compress(self, data_list):
return data_list[0] + ' ' + data_list[1] + ' ' + data_list[2]
class AddressFormNew(forms.ModelForm):
postal = forms.CharField(widget=forms.TextInput(attrs={'class':'small'}))
address = AddressField()
city = forms.CharField(widget=forms.TextInput(attrs={'class':'big'}))
class Meta:
model = Address
好吧,我无法弄清楚如何在我的视图中使用此表单。我正在尝试:
@login_required
def render_addresses(request):
address_form = AddressFormNew()
if request.method == 'POST':
address_form = AddressFormNew(request.POST)
if address_form.is_valid():
address_form.save()
return HttpResponse('ok')
else:
return HttpResponse(address_form.errors['address'])
return render_to_response('profile/addresses.html',context_instance=RequestContext(request,{'address_form':address_form}))
结果,Django给了我这个错误:
输入值列表。
此外,当我尝试打印request.POST.items()时,它将地址响应作为3个分隔数据。
我在这里很丢失,我必须将我的地址数据放在一行。我应该如何通过保存表单来实现这一目标?
如果有人给我一个明确的解释,我真的很感激。
答案 0 :(得分:4)
以下是我在代码中看到的应该解决的问题:
(1)。在调用超类的 init 时,在AddressField init 方法中,您应该将 fields 作为参数传递。
class AddressField(forms.MultiValueField): def __init__(self,*args,**kwargs): fields = ( forms.CharField(widget=forms.TextInput(attrs={'class':'big'})), forms.CharField(widget=forms.TextInput(attrs={'class':'big'})), forms.CharField(widget=forms.TextInput(attrs={'class':'big'})), ) self.widget = AddressFieldWidget(widgets=[fields[0].widget, fields[1].widget, fields[2].widget]) super(AddressField,self).__init__(fields=fields,*args,**kwargs)
(2)。你是对的,你的value_from_datadict是不正确的。关键是,您已使用MultiValueField来填充窗口小部件。因此,窗口小部件必须将值列表返回到AddressField
中的相应子字段你可以调用超类的 value_from_datadict 来完成这项工作,或者使用它(我认为是相同的):
def value_from_datadict(self,data,files,name): res = [] for i, widget in enumerate(self.widgets): res.append(widget.value_from_datadict(data, files, name + '_%s' % i)) return res
理解基本概念很重要。您也可以将此小部件与CharField一起使用。在这种情况下,value_from_datadict应该返回一个字符串。但由于您使用的是MultiValueField,因此返回类型应该是一个列表。这就是将“输入值列表”作为错误
的原因如果您打算从存储在数据库中的值到表单重新创建地址第1,2和3行,那么您不应该使用空格作为分隔符。如果不是那么一切都很好:)
我没有在文档或网络上找到MultiValueField和MultiWidget的好例子,但由于我必须在我的一个项目中使用它们,我不得不自己深入研究。希望这会有所帮助:)
答案 1 :(得分:0)
我认为你还需要一个解压缩方法,而fields =(...)应该在__init__
之外
答案 2 :(得分:-1)
Django的源文件通常可以成为灵感的良好来源。 (双关语无意)你可以查看django.forms.fields.SplitDateTimeField
,它提供了一个如何做类似事情的例子。
一些可能的错误可能是您在初始化(super(AddressField,self).__init__()
)后设置了self.widget,因此该字段只使用标准小部件。并且您没有向fields
发送__init__
。以下是我认为你可以做AddressField
的快速草稿:
class AddressField(forms.MultiValueField):
widget = MultiValueWidget(widgets=(forms.TextInput, forms.TextInput, forms.TextInput)
def __init__(self, *args, **kwargs):
fields = (
forms.CharField(widget=forms.TextInput(attrs={'class':'big'})),
forms.CharField(widget=forms.TextInput(attrs={'class':'big'})),
forms.CharField(widget=forms.TextInput(attrs={'class':'big'})),
)
super(AddressField,self).__init__(fields, *args, **kwargs)
def compress(self, data_list):
return "%s %s %s" % data_list[0:2]
这排除了你在AddressFieldWidget
中所拥有的所有笨蛋,因为我坦率地不明白你想要做什么:)