Фильтровать поле ManyToMany в Django Admin
У меня есть объект, имеющий отношение многие ко многим с другим объектом.
В Django Admin это приводит к очень длинному списку в окне множественного выбора.
Мне бы хотелось отфильтровать отношение ManyToMany, чтобы я выбирал только те категории, которые доступны в городе, который выбрал клиент.
Это возможно? Должен ли я создать виджет для него? И если так - как мне скопировать в него поведение из стандартного поля ManyToMany, так как я хотел бы также использовать функцию filter_horizontal.
Это мои упрощенные модели:
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)
7 ответов
Хорошо, это мое решение с использованием вышеуказанных классов. Я добавил еще несколько фильтров для правильной фильтрации, но я хотел, чтобы код читался здесь.
Это именно то, что я искал, и я нашел свое решение здесь: http://www.slideshare.net/lincolnloop/customizing-the-django-admin (слайд 50)
Добавьте следующее в мой 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
Это фильтрует список "категорий", не удаляя никакой функциональности! (то есть: у меня все еще может быть мой любимый фильтр_горизонтальный:))
ModelForms очень мощные, я немного удивлен, что они больше не рассматриваются в документации / книге.
Насколько я понимаю, вы в основном хотите отфильтровать показанные варианты выбора по некоторым критериям (категория по городу).
Вы можете сделать именно это с помощью limit_choices_to
атрибут models.ManyToManyField
, Так что изменив определение модели как...
class Customer(models.Model):
name = models.CharField(max_length=200)
city = models.ForeignKey(City)
categories = models.ManyToManyField(Category, limit_choices_to = {'available_in': cityId})
Это должно работать, как limit_choices_to
, доступен для этой цели.
Но стоит отметить одну вещь, limit_choices_to
не действует при использовании ManyToManyField с пользовательской промежуточной таблицей. Надеюсь это поможет.
Другой способ с formfield_for_manytomany
в 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)
Учитывая, что "автомобили" - это поле ManyToMany.
Проверьте эту ссылку для получения дополнительной информации.
Я думаю, это то, что вы ищете:
http://blog.philippmetzler.com/?p=52
мы используем django-smart-select:
http://github.com/digi604/django-smart-selects
Philipp
Поскольку вы выбираете город и категории клиента в одной и той же форме, вам понадобится некоторый JavaScript, чтобы динамически свести селектор категорий к тем категориям, которые доступны в выбранном городе.
Как говорит Райан, должен быть какой-то javascript для динамического изменения параметров в зависимости от того, что выбирает пользователь. Размещенное решение работает, если город сохранен и административная форма перезагружена, то есть, когда фильтр работает, но подумайте о ситуации, когда пользователь хочет отредактировать объект, а затем изменить раскрывающийся список городов, но параметры в категории не обновятся.
Category.objects.filter(available_in=cityobject)
Это должно сделать это. В представлении должен быть выбран город, выбранный пользователем, либо в запросе, либо в качестве параметра этой функции представления.