I want to use a form to generate a new object (say a Book) from a Person\'s page such that the new Book is automatically associated with that Person via a foreign key, but I
Since the ID is sent with the request, your form does not need a person field. Instead, you need to add the person before the Book is saved.
Your form should be:
class BookForm(forms.ModelForm):
class Meta:
model = Book
fields = ('title',)
Your views should be something like this:
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})
In your urls.py
, make sure you are passing the id to this view:
url(r'book/add/(?P<person_id>\d+)/$', create_book, name='create_book')
You would call it like this http://localhost:8000/book/add/1/
(if you are adding for person id 1).
You also don't need to give your own primary key, django will add one by default to all models, so your Person
model should be simply:
class Person(models.Model):
name = models.CharField(max_length=200) # Or some other field
Now, your person model will have an automatic pk
property, which will be the primary key (whatever it is actually called in your database).
You're going at it the wrong way: the person is not user input, so this information should not reside in the form. You can override the form_valid
method as follows:
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)
This will set the person_id
attribute on the instance used by the form to save the data, and then call the super
method to save that instance and return a redirect.