Django ModelForms中的额外字段:我能看到它们,但无法保存到模型中,为什么?
在我的Django应用中,我使用了一个ModelForm来让用户输入街道地址。我的目标是先清理这个地址,然后进行美国邮政服务(USPS)的验证,最后进行地理编码。如果这些步骤都成功了,我想把原始和清理后的地址都保存到我的Location
模型中,模型的结构如下。
from localflavor.us.us_states import US_STATES
from django.contrib.gis.db import models
class Location(models.Model):
# I want the user to enter these fields using a Model Form
streetAddress = models.CharField(blank=False, null=False, max_length=300)
city = models.CharField(null=False, blank=False, max_length=50)
state = USStateField(choices = US_STATES, null=False,)
zip = models.CharField(null=False, max_length=10, )
# I want to automatically derive these fields without any user intervention.
# These fields are going to be calculated during the form validation process.
cleanedStreetAddress = models.CharField(blank=False, null=False, max_length=300)
cleanedCity = models.CharField(null=True, blank=True, max_length=50)
cleanedState = USStateField(choices = US_STATES, null=False,)
cleanedZip5 = models.CharField(null=False, max_length=5, )
cleanedZip4 = models.CharField(null=False, max_length=4, )
geoCoords = models.PointField(null=False, blank=False,)
在对应的ModelForm(叫做LocationForm
)中,我设置了fields = ["streetAddress", "city", "state", "zip",]
。其余的六个字段我通过手动添加到LocationForm.clean()
方法返回的字典中来填充。到目前为止,一切都很好,没有问题。
在对应的基于类的视图中,我在form_valid()
方法中处理这个表单,代码如下:
class InputLocationView(FormView):
template_name = "helloWorld.html"
form_class = LocationForm
success_url = "/helloWorld"
def form_valid(self, form):
print "form.cleaned_data = %s" % form.cleaned_data
###
# Output of the line above:
# form.cleaned_data = {'cleanedZip4': '0000', 'streetAddress': u'123 Main Street',
# 'zip': u'90210', 'cleanedStreetAddress': '123 MAIN ST', 'cleanedState': 'CO',
# 'geoCoords': <Point object at 0x10a1b4e20>, 'state': u'CO', 'city': u'Anytown',
# 'cleanedCity': 'ANYTOWN', 'cleanedZip5': '90210'}
###
print "form.cleaned_data['geoCoords'] = (%s, %s)" % (form.cleaned_data['geoCoords'].x, form.cleaned_data['geoCoords'].y)
# Output of the line above: form.cleaned_data['geoCoords'] = (-77.260768, 39.113707)
newLocation = form.save(commit=False)
newLocation.save()
从我上面的注释可以看到,我在LocationForm.clean()中添加的派生数据在这个基于类的视图中是存在的。这是个好消息。然而,当执行到newLocation.save()时,却出现了以下错误:
null value in column "geoCoords" violates not-null constraint
DETAIL: Failing row contains (3, 123 Main Street, , Anytown, CO, 90210, , null,
, , , null)
为什么newLocation.save()
没有包含我所有的派生数据,而这些数据在form.cleaned_data
字典中是明显存在的呢?我该如何确保所有来自form.cleaned_data
的数据都能被包含在SQL插入语句中呢?
2 个回答
我记得没错的话,只有在 ModelForm.Meta.fields
列表中提到的字段,才会自动从 cleaned_data
中获取数据。与其把你自己计算出来的数据放进 cleaned_data
,不如直接把它们设置到 self.instance
上,这样在你的 ModelForm
中会更简单。
ModelForm
这个工具大概只会填充你在 fields
中指定的那些字段。解决这个问题的方法是重写 ModelForm.save()
这个函数。可以这样做:
class LocationForm(ModelForm):
...
def save(self, commit=True, **kwargs):
# create the instance but don't commit it to the database
location = super(LocationForm, self).save(commit=False, **kwargs)
# now set your cleaned fields on the model instance
location.cleanedStreetAddress = ...
if commit:
location.save()
return location
想了解更多信息,可以查看 关于 save()
的文档。