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

时间:2014-07-17 21:04:38

标签: django django-forms

我想使用表单从Person页面生成一个新对象(比如一本书),以便新书通过外键自动与该Person关联,但是我遇到了使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,
        }

创建图书的视图(也是人的pkp_id)):

class AddBook(CreateView):
    model = Book

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

  • 使用get_initial预填充Person字段,但由于某些原因,输入设置为隐藏(令人沮丧),这会消失。
  • 修改视图中的form_valid方法,但这仅在表单经过验证后才会发生,因此我需要在此之前添加Person。
  • 修改表单类中的clean_person方法,但只有在clean方法验证表单后才会发生。

目前,我正在尝试覆盖clean方法。但是,在表格已经发送清理之后,我不知道如何获得此人。在视图中,我可以使用Patient.objects.get(p_id=self.kwargs.get('pk'))访问它。

我是否可以通过某种方式将数据添加到我的视图中(作为基于类的视图),它不会被剥离 OR 是否有某些方法可以访问此时是人或p_id外键,以clean方法添加数据?

2 个答案:

答案 0 :(得分:8)

你的做法是错误的:这个人不是用户输入,所以这些信息不应该存在于表格中。您可以按如下方式覆盖form_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_id属性,然后调用super方法保存该实例并返回重定向。

答案 1 :(得分:3)

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

您的表格应该是:

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')

您可以将其称为http://localhost:8000/book/add/1/(如果您要为人员ID 1添加)。

您也不需要提供自己的主键,django默认会为所有模型添加一个,因此您的Person模型应该只是:

class Person(models.Model):
    name = models.CharField(max_length=200) # Or some other field

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