在 Django 中使用自定义外键字段保存表单中的数据

Posted

技术标签:

【中文标题】在 Django 中使用自定义外键字段保存表单中的数据【英文标题】:save data from form with custom foreign key field in django 【发布时间】:2011-11-05 08:19:15 【问题描述】:

我有以下模型类:

class ContactPerson(models.Model):            
    name = models.CharField(max_length=30)

    def __unicode__(self):
        return self.name

class Appartment(models.Model):
    contact_person = models.ForeignKey(ContactPerson)

问题:在模板文件中我想让用户填写联系人姓名,所以我覆盖contact_person字段如下:

class AppartmentSellForm(ModelForm):
    contact_person = forms.CharField(max_length=30)

    class Meta:
        model = Appartment

在我的视图函数中,我正在执行以下操作来保存提交的表单中的数据:

def appartment_submit(request):
    if request.method == "POST":
        form = AppartmentSellForm(request.POST)
        if form.is_valid():
            appartment = form.save(commit=False) # ERROR HERE
            cp = models.ContactPerson(name=form.cleaned_data['contact_person'])
            appartment.contact_person = cp
            appartment.save()
            form.save();
            return HttpResponseRedirect('/sell/')
    else:
        form = AppartmentSellForm()
    return render_to_response('sell_appartment_form.html', 'form' : form)

错误信息

#ValueError at /sell/sell_appartment/appartment_submit/

Cannot assign "u'blabla'": "Appartment.contact_person" must be a "ContactPerson" instance.**

我正在使用 SQLite 和 django 版本 1.1.1

问题:如何解决这个问题?

【问题讨论】:

那是一个相当旧的 Django 版本,你没有使用 1.3 有什么原因吗? 在修复所有错误和弃用警告后,更新可能会减轻您的进度,这确实更好。更多关于主题(具有尘土飞扬的 Django 技能),如果你打印 cp 变量,你会得到你所期望的吗? @Jasper Kennis,代码在 cp 之前失败。但是,是的,如果我在上面注释掉一行并打印出来,这就是我所期望的。好吧,我正在升级我的 django 版本... 嗯,你能改变包含在表单中试图保存的值吗?在这种情况下,您应该将定义 cp 的行向上移动,并在对其运行 save() 之前更改表单值。 【参考方案1】:

您可以执行以下操作之一:

    尝试exclude contact_person 字段,如提到的in point 3 over here 或者您不能覆盖 ModelForm 中的字段,Django 会将其呈现为 ModelChoiceField,除非您确实希望人们输入名称而不是下拉列表可供选择。

【讨论】:

如果你exclude它,它可能不会尝试将字符串保存为ForeignKey 你试过了吗? ...或者您可以尝试@adamnfish 的建议。【参考方案2】:

我认为您放在视图中的代码更适合 ModelForm 的验证。

覆盖模型表单的clean_contact_person 方法并在其中添加代码,以便a) 检查名称是否有效,如果有效,b) 将表单字段的值设置为实际的 ContactPerson 实例。

类似的东西:(在我的脑海中)

class AppartmentSellForm(ModelForm):
    contact_person = forms.CharField(max_length=30)

    class Meta:
        model = Appartment

    def clean_contact_person(self):
        name = self.cleaned_data['contact_person']
        # check the name if you need to
        try:
            # maybe check if it already exists?
            person = models.ContactPerson.objects.get(name=name)
        except ContactPerson.DoesNotExist:
            person = models.ContactPerson(name=name)
            # you probably only want to save this when the form is saved (in the view)
        return person

您的视图可能仍需要使用commit=False(因为您需要保存 ContactPerson 记录)。您可以使用save_m2m 方法执行此操作。

the ModelForm documentation 中有更多关于save_m2m 的信息,the validation documentation 中有关于清理字段的信息。

希望对你有帮助,祝你好运!

【讨论】:

以上是关于在 Django 中使用自定义外键字段保存表单中的数据的主要内容,如果未能解决你的问题,请参考以下文章

使用注册表单添加到自定义用户字段(django)

如何使用django自定义表单保存多个到多个字段

django admin中的外键表单字段

Django中的自定义纬度/经度表单字段

Django allauth 自定义登录表单未呈现自定义用户模型中的所有字段

将查询集传递给 django 内联表单中的外键字段