我想使用表单从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,
}
创建图书的视图(也是人的pk
(p_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
方法添加数据?
答案 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
属性,该属性将是主键(无论数据库中实际调用它是什么)。