Filter ManyToMany box in Django Admin
Solution 1
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.
Solution 2
As far as i can understand you, is that you basically want to filter the shown choices according to some criteria (category according to city).
You can do exactly that by using limit_choices_to
attribute of models.ManyToManyField
. So changing your model definition as...
class Customer(models.Model):
name = models.CharField(max_length=200)
city = models.ForeignKey(City)
categories = models.ManyToManyField(Category, limit_choices_to = {'available_in': cityId})
This should work, as limit_choices_to
, is available for this very purpose.
But one things to note, limit_choices_to
has no effect when used on a ManyToManyField with a custom intermediate table. Hope this helps.
Solution 3
Another way is with formfield_for_manytomany
in Django Admin.
class MyModelAdmin(admin.ModelAdmin):
def formfield_for_manytomany(self, db_field, request, **kwargs):
if db_field.name == "cars":
kwargs["queryset"] = Car.objects.filter(owner=request.user)
return super(MyModelAdmin, self).formfield_for_manytomany(db_field, request, **kwargs)
Considering that "cars" are the ManyToMany field.
Check this link for more info.
Solution 4
I think this is what you're looking for:
http://blog.philippmetzler.com/?p=52
we use django-smart-selects:
http://github.com/digi604/django-smart-selects
Philipp
Solution 5
Since you're selecting the customer's city and categories in the same form, you would need some javascript to dynamically whittle down the categories selector to just the categories available in the city selected.
schmilblick
Web application developer. Particularly interested in projects using Python. Always interested in new projects, profit or non profit.
Updated on June 05, 2021Comments
-
schmilblick almost 3 years
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)