Настройка поля администратора 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

Мне пришлось сделать это на днях, это немного хлопотно, но выполнимо, и я использовал его несколько раз с тех пор, как придумал этот метод.

Шаги

  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)

  1. Скрыть строки, которые еще не могут быть заполнены.
window.addEventListener('DOMContentLoaded', (event) => {
    django.jQuery("div.field-item_type").css('display', '');
    django.jQuery("div.field-plant").css('display', '');
});
  1. Добавьте слушателей событий для обновления зависимых полей
# 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)
});

  1. реализуйте 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, чтобы делать это автоматически. Если кто-то уже знает такой пакет, мне было бы интересно узнать о нем.

Вернуться на верх