I have an object with a ManyToMany relation with another object.
In the Django Admin this results in a very long list in a multiple select box.
I'd like to filter the ManyToMany relation so I only fetch Categories that are available in the City that the Customer has selected.
Is this possible? Will I have to create a widget for it? And if so—how do I copy the behavior from the standard ManyToMany field to it, since I would like the filter_horizontal
function as well.
These are my simplified models:
class City(models.Model): name = models.CharField(max_length=200) class Category(models.Model): name = models.CharField(max_length=200) available_in = models.ManyToManyField(City) class Customer(models.Model): name = models.CharField(max_length=200) city = models.ForeignKey(City) categories = models.ManyToManyField(Category)
Nope. Django filters operate at the database level, generating SQL. To filter based on Python properties, you have to load the object into Python to evaluate the property--and at that point, you've already done all the work to load it.
One of the most powerful parts of Django is the automatic admin interface. It reads metadata from your models to provide a quick, model-centric interface where trusted users can manage content on your site. The admin's recommended use is limited to an organization's internal management tool.
For Django 1.4-1.7, list_filter allows you to use a subclass of SimpleListFilter . It should be possible to create a simple list filter that lists the values you want.
Ok, this is my solution using above classes. I added a bunch more filters to filter it correctly, but I wanted to make the code readable here.
This is exactly what I was looking for, and I found my solution here: http://www.slideshare.net/lincolnloop/customizing-the-django-admin#stats-bottom (slide 50)
Add the following to my admin.py:
class CustomerForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(CustomerForm, self).__init__(*args, **kwargs) wtf = Category.objects.filter(pk=self.instance.cat_id); w = self.fields['categories'].widget choices = [] for choice in wtf: choices.append((choice.id, choice.name)) w.choices = choices class CustomerAdmin(admin.ModelAdmin): list_per_page = 100 ordering = ['submit_date',] # didnt have this one in the example, sorry search_fields = ['name', 'city',] filter_horizontal = ('categories',) form = CustomerForm
This filters the "categories" list without removing any functionality! (ie: i can still have my beloved filter_horizontal :))
The ModelForms is very powerful, I'm a bit surprised it's not covered more in the documentation/book.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With