Настройка поля администратора django на основе другого выпадающего поля
У меня есть простое приложение Django с тремя моделями:
class Category(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(("Description"))
class ItemType(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(("Description"))
category = models.ForeignKey(Category, on_delete=models.CASCADE)
class Plant(models.Model):
category = models.ForeignKey(Category , on_delete=models.SET_NULL , null=True)
type = models.ForeignKey(ItemType, on_delete=models.SET_NULL,null = True)
name = models.CharField()
что мне нужно в админ панели когда я выбираю категорию выпадающий тип фильтруется на основе этого например у меня есть категория1 и категория2 и тип1 связан с категорией1 и тип2 связан с категорией2 когда я выбираю категорию1 из выпадающего списка выпадающий тип показывает только тип1
Мне пришлось сделать это на днях, это немного хлопотно, но выполнимо, и я использовал его несколько раз с тех пор, как придумал этот метод.
Шаги
- Добавьте необходимую информацию в контекст в
render_change_form
.
Для вашего случая я бы предположил, что вам нужно что-то вроде этого
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
# Implement get_map to return a hierarchical dict that represents your category, item type, and plant
context['map'] = self.get_map()
return super().render_change_form(request, context, add, change, form_url, obj)
- Скрыть строки, которые еще не могут быть заполнены.
window.addEventListener('DOMContentLoaded', (event) => {
django.jQuery("div.field-item_type").css('display', '');
django.jQuery("div.field-plant").css('display', '');
});
- Добавьте слушателей событий для обновления зависимых полей
# When category is changed, you'll need to update options for item_type and plant
django.jQuery("select[name=category]").change(function () {
let category = django.jQuery(this)
update_item_type(category)
update_plant(django.jQuery('select[name=category]'))
});
# When item_type is changed, you'll only need to plant options
django.jQuery("select[name=item_type]").change(function () {
let item_type = django.jQuery(this)
update_plant(item_type)
});
- реализуйте
update_item_type
иupdate_plant
для обновления опций в соответствующих полях
Они будут выглядеть примерно так
function update_item_type(plant) {
let starting_item_type = django.jQuery("select[name=item_type]").val()
if (plant.val() === '') {
django.jQuery("div.field-item_type").css('display', 'none');
} else {
let item_type_dict = {{ item_type_dict|safe }};
let item_type_dom = django.jQuery('#id_item_type');
item_type_dom.text('')
django.jQuery.each(item_type_dict[plant.val()], function(index, element) {
item_type_dom.append('<option value="' + element[0] + '">' + element[1] + '</option>');
});
django.jQuery("div.field-item_type").css('display', '');
django.jQuery("select[name=item_type]").val(starting_item_type)
}
}
Получить доступ к вашему словарю из страны Django можно следующим образом
let map = {{ map|safe }};
Послесловие
Вероятно, мне следует создать пакет Django, чтобы делать это автоматически. Если кто-то уже знает такой пакет, мне было бы интересно узнать о нем.