Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Modify Choices of ModelMultipleChoiceField

Let's say I have some contrived models:

class Author(Model):
   name = CharField()

class Book(Model):
   title = CharField()
   author = ForeignKey(Author)

And let's say I want to use a ModelForm for Book:

   class BookForm(ModelForm):
      class Meta:
         model = Book

Simple so far. But let's also say that I have a ton of Authors in my database, and I don't want to have such a long multiple choice field. So, I'd like is to restrict the queryset on the BookForm's ModelMultipleChoiceField author field. Let's also say that the queryset I want can't be chosen until __init__, because it relies on an argument to be passed.

This seems like it might do the trick:

class BookForm(ModelForm):
   class Meta:
      model = Book

   def __init__(self, letter):
      # returns the queryset based on the letter
      choices = getChoices(letter)
      self.author.queryset = choices

Of course, if that just worked I wouldn't be here. That gets me an AttributeError. 'BookForm' object has no attribute 'author'. So, I also tried something like this, where I try to override the ModelForm's default field and then set it later:

class BookForm(ModelForm):
   author = ModelMultipleChoiceField(queryset=Author.objects.all())

   class Meta:
      model = Book

   def __init__(self, letter):
      choices = getChoices(letter)
      self.author.queryset = choices

Which produces the same result.

Anyone know how this is intended to be done?

like image 655
Brian Avatar asked Apr 10 '09 17:04

Brian


2 Answers

Although Carl is correct about the fields, you're also missing a super class call. This is how I do it:

class BookForm(ModelForm):
    author = ModelMultipleChoiceField(queryset=Author.objects.all())

    class Meta:
        model = Book

    def __init__(self, *args, **kwargs):
        letter = kwargs.pop('letter')
        super(BookForm, self).__init__(*args, **kwargs)
        choices = getChoices(letter)
        self.fields['author'].queryset = choices
like image 191
Paolo Bergantino Avatar answered Sep 22 '22 22:09

Paolo Bergantino


Form objects don't have their fields as attributes, you need to look in the "fields" attribute, which is a dictionary:

self.fields['author'].queryset = choices

If you want to fully understand what's going on here, you might be interested in this answer - it's about Models, but Forms work similarly.

like image 8
Carl Meyer Avatar answered Sep 19 '22 22:09

Carl Meyer