2

Possible Duplicate:
How do I filter ForeignKey choices in a Django ModelForm?

Say I have some models that look like this:

from django.db import models
from django.contrib.auth.models import User

class Author(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    owner = models.ForeignKey(User)

class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author)
    owner = models.ForeignKey(User)

If I create a ModelForm for the Book model, users are allowed to select from all authors, not just the ones they own. How would I create a ModelForm for the Book model that lets the user select only authors that s/he owns?

Community
  • 1
  • 1
Joe Mornin
  • 8,766
  • 18
  • 57
  • 82
  • Refer: http://stackoverflow.com/questions/291945/how-do-i-filter-foreignkey-choices-in-a-django-modelform – Rohan Jul 07 '12 at 05:22
  • I think you may want to use a onetoone relationship. One to one relationships return a return a single object. – Frantz Romain Jul 07 '12 at 05:33

1 Answers1

4

You can override the model form's __init__ method and restrict the queryset for the author model choice field.

class BookForm(forms.ModelForm):

    class Meta:
        model = Book
        # exclude the owner and set it in the view
        exclude = ('owner',) 

    def __init__(self, *args, **kwargs):
        super(BookForm, self).__init__(*args, **kwargs)
        if self.instance.owner:
            self.fields['author'].queryset = Author.objects.filter(owner=self.instance.owner)

In your view, make sure that you instantiate the form with an instance that already has the owner set. For example to add a book, it would look something like this:

def add_book(request):
    book = Book(owner=request.owner)
    form = BookForm(data=request.POST or None, instance=book)
    if form.is_valid():
        book.save()
        return HttpResponseRedirect('/success-url/')
    return render(request, "my_template.html", {'form': form})
Alasdair
  • 298,606
  • 55
  • 578
  • 516