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

5 投票
2 回答
4005 浏览
提问于 2025-04-17 00:28

我有以下的模型类:

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)

问题:在模板文件中,我希望用户填写联系人的名字,所以我这样重写了联系人的字段:

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

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

2 个回答

0

你可以选择以下其中一种方法:

  1. 试着 排除 contact_person 这个字段,具体可以参考 这里的第3点
  2. 或者你可以不在你的 ModelForm 中覆盖这个字段,这样Django会自动把它显示为一个 ModelChoiceField,除非你真的希望用户手动输入名字,而不是从下拉列表中选择。
2

我觉得你在视图中写的代码,放到模型表单的验证里会更合适。

你可以重写模型表单的 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 方法来做到这一点。

关于 save_m2m 的更多信息,可以查看 模型表单的文档,还有关于清理字段的信息,可以参考 验证文档

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

撰写回答