Django在表单中自动设置外键(使用基于类的视图)

Django在表单中自动设置外键(使用基于类的视图),django,django-forms,Django,Django Forms,我想使用一个表单从一个人的页面生成一个新对象(比如一本书),这样新书就可以通过外键自动与此人关联,但是我在让此人与表单正确关联和保存时遇到了麻烦。对于我的模型,我有: class Person(models.Model): p_id = models.PositiveIntegerField(primary_key=True, unique=True) class Book(models.Model): person = models.ForeignKey(Person)

我想使用一个表单从一个人的页面生成一个新对象(比如一本书),这样新书就可以通过外键自动与此人关联,但是我在让此人与表单正确关联和保存时遇到了麻烦。对于我的模型,我有:

class Person(models.Model):
    p_id = models.PositiveIntegerField(primary_key=True, unique=True)

class Book(models.Model):
    person = models.ForeignKey(Person)
    title = models.CharField(max_length=100)
然后我有一个自定义表单来创建一本书:

class AddBookForm(forms.ModelForm):
    class Meta:
        model = Book
        fields = ('title', 'person',)
        widgets = {
            'person': forms.HiddenInput,
        }
以及创建该书的视图(该视图还提供了该人的
pk
p_id
):

我尝试了各种方法来实现这一点:

  • 使用
    get_initial
    预先填充Person字段,但由于某些原因,当输入设置为hidden(令人沮丧)时,这会消失
  • 在视图中修改
    form\u valid
    方法,但这只发生在表单已经被验证之后,因此我需要在此之前添加Person
  • 修改表单类中的
    clean\u person
    方法,但这仅在表单通过
    clean
    方法验证后发生
目前,我正在尝试覆盖
clean
方法。然而,我不知道如何在这一点上的人,在表格已经被发送清洁。在视图中,我可以使用
Patient.objects.get(p_id=self.kwargs.get('pk'))访问它


是否有某种方法可以将数据添加到我视图中的表单中(作为基于类的视图),使其不会被剥离是否有某种方法可以在此时访问Person或
p\u id
外键,以
clean
方法添加数据?

您的做法是错误的:Person不是用户输入,所以这些信息不应该存在于表单中。您可以按如下方式重写
form\u valid
方法:

class AddBook(CreateView):
    model = Book

    def form_valid(self, form):
        form.instance.person_id = self.kwargs.get('pk')
        return super(AddBook, self).form_valid(form)

这将在表单用于保存数据的实例上设置
person\u id
属性,然后调用
super
方法保存该实例并返回重定向

由于ID随请求一起发送,因此表单不需要person字段。相反,您需要在保存书籍之前添加此人

您的表格应为:

class BookForm(forms.ModelForm):
    class Meta:
        model = Book
        fields = ('title',)
你的观点应该是这样的:

from django.shortcuts import get_object_or_404
from django.shortcuts import render, redirect

def create_book(request, person_id):

     # If the person_id is not valid, don't go forward.
     # return a 404 instead.

     person = get_object_or_404(Person, pk=person_id)

     book_form = BookForm(request.POST or None)
     if book_form.is_valid():
         new_book = book_form.save(commit=False) # Don't save it yet
         new_book.person = person # Add person
         new_book.save() # Now save it
         return redirect('/')

     return render(request, 'book_form.html', {'form': book_form})
urls.py
中,确保将id传递给此视图:

url(r'book/add/(?P<person_id>\d+)/$', create_book, name='create_book')

现在,您的个人模型将具有一个自动的
pk
属性,该属性将是主键(无论在数据库中实际调用什么)。

如果用户未选择该书,您如何知道该书与哪个人关联?他们单击“创建书”在一个人的页面上,该页面的id将随请求一起发送。我几乎已经尝试过了。不过有两个窍门:我必须将该字段从表单中取出,以便它进行验证,我一直在尝试
form.instance.p\u id
而不是
person\u id
。我仍然不完全理解为什么它是
person\u id.
我得到的
person
部分,因为那是字段名。但是为什么
\u id
?在这种情况下,这是否等同于pk
?是的:外键总是由两个属性组成;外部对象(模型实例)和外键(引用对象的主键)。外键属性总是在外键模型属性的名称后附加
\u id
,这是实际保存到数据库中的字段。实际上,您必须将字段从表单中去掉。注意,在Python 3中,对的调用可以简化为
super()
这是一个非常不基于分类的视图;)提出了同样的问题,如果他需要根据peraon实例做一些逻辑,会怎么样?按照您的方式,在form clean()方法中无法使用此人
url(r'book/add/(?P<person_id>\d+)/$', create_book, name='create_book')
class Person(models.Model):
    name = models.CharField(max_length=200) # Or some other field