Django ModelForms中的额外字段:我可以看到它们,但无法将它们保存到模型中。为什么?

时间:2014-08-19 16:25:37

标签: python django django-forms

在我的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()方法返回的字典中来填充剩余的6个字段。到现在为止还挺好。没问题。

在相应的基于类的视图中,我使用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 Insert语句?

2 个答案:

答案 0 :(得分:1)

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

有关详细信息,请参阅documentation on save()

答案 1 :(得分:0)

如果我没有记错的话,只会从ModelForm.Meta.fields自动分配cleaned_data列表中指定的字段。您应该直接在cleaned_data中的self.instance上设置,而不是将您的派生数据放入ModelForm