Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Need help with Django ModelForm: How to filter ForeignKey/ManyToManyField?

Alright, I'm having a hard time explaining this, let me know if I should fill you in on more details.

My url looks like this: http://domain.com/<category>/
Each <category> may have one or many sub categories.

I want the category page to have a form with a select box (among other fields) containing the category sub-categories. I've currently hard coded the form in one of the templates, but I want to make it reflect the model directly.

In my currently hard coded solution, I have in my category view:

s = Category.objects.filter(parents__exact=c.id)  

that the form template iterates through and prints out the select box (see model code below)

I'm guessing I want a ModelFormSet with an init that filters out the categories, but I can't seem to find how to do it in the docs.

Been looking at How do I filter ForeignKey choices in a Django ModelForm? as well, but I can't get it to work properly.

My models

# The model that the Form should implement
class Incoming(models.Model):
    cat_id = models.ForeignKey(Category)
    zipcode = models.PositiveIntegerField()
    name = models.CharField(max_length=200)
    email = models.EmailField()
    telephone = models.CharField(max_length=18)
    submit_date = models.DateTimeField(auto_now_add=True)
    approved = models.BooleanField(default=False)

# The categories, each category can have none or many parent categories
class Category(models.Model):
    name = models.CharField(max_length=200, db_index=True)
    slug = models.SlugField()
    parents = models.ManyToManyField('self',symmetrical=False, blank=True, null=True)

    def __unicode__(self):
        return self.name

My form

class IncomingForm(ModelForm):
    class Meta:
        model = Incoming
like image 337
schmilblick Avatar asked Jun 07 '09 16:06

schmilblick


2 Answers

As you say, you need a modelform class with a custom __init__:

class IncomingForm(ModelForm):
    class Meta:
        model = Incoming

    def __init__(self, *args, **kwargs):
        super(IncomingForm, self).__init__(*args, **kwargs)
        if self.instance:
            self.fields['parents'].queryset = Category.objects.filter(
                                              parents__exact=instance.id)
like image 87
Daniel Roseman Avatar answered Sep 27 '22 22:09

Daniel Roseman


I would edit Daniel Rosemans reply and vote it winner, but since i cant edit it i will post the correct answer here:

class IncomingForm(ModelForm):
    class Meta:
        model = Incoming

    def __init__(self, *args, **kwargs):
        super(IncomingForm, self).__init__(*args, **kwargs)
        if self.instance:
            self.fields['cat_id'].queryset = Category.objects.filter(
                    parents__exact=self.instance.id)

The difference is self.fields['cat_id'] (correct) vs self.fields['parents'] (wrong, we both made the same mistake)

like image 22
schmilblick Avatar answered Sep 27 '22 23:09

schmilblick