django-mptt: Как автоматически выбирать детей в администраторе при выборе родителя?

#django #django-forms #django-mptt

Вопрос:

У меня есть некоторые проблемы при выборе родителя — дети не выбираются автоматически. Например, когда я выбираю Cluster #2 его дочерние элементы ( Store #1 и Store #2 ), которые не выбираются:

введите описание изображения здесь

Как я могу это исправить?

Это важно, потому что мне нужно создавать ссылки «многие ко многим» (с отклонением от единицы) только с stores (с листами).

Модели:

 from django.db import models
from mptt.fields import TreeForeignKey
from mptt.models import MPTTModel


class Orgunit(MPTTModel):
    name = models.CharField(
        max_length=100
    )
    type = models.CharField(
        choices=[
            ('MACRO', 'Макро'),
            ('CLUSTER', 'Кластер'),
            ('KUST', 'Куст'),
            ('STORE', 'Магазин')
        ],
        max_length=100
    )
    parent = TreeForeignKey(
        'self',
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='children'
    )

    def __str__(self):
        return self.name


class Deviation(models.Model):
    name = models.CharField(max_length=100)
    number = models.PositiveIntegerField(null=True)
    orgunits = models.ManyToManyField('orgunits.Orgunit')

    def __str__(self):
        return self.name
 

Администратор:

 from django.contrib import admin

from deviations.forms import MyForm
from deviations.models import Deviation


@admin.register(Deviation)
class DeviationAdmin(admin.ModelAdmin):
    form = MyForm
 

Форма:

 from django.forms import ModelForm, widgets
from mptt.forms import TreeNodeMultipleChoiceField

from orgunits.models import Orgunit


class MyForm(ModelForm):
    orgunits = TreeNodeMultipleChoiceField(queryset=Orgunit.objects.all(), widget=widgets.SelectMultiple())

    class Meta:
        model = Orgunit
        fields = '__all__'
 

Ответ №1:

У меня есть приведенный ниже код в качестве примера :

  private void CheckAllChildNodes(TreeNode treeNode, bool nodeChecked)
    {
        foreach (TreeNode node in treeNode.Nodes)
        {
            node.Checked = nodeChecked;
            if (node.Nodes.Count > 0)
            {
                this.CheckAllChildNodes(node, nodeChecked);
            }
        }
    }
    private void treeView_AfterCheck(object sender, TreeViewEventArgs e)
    {
        if (e.Action != TreeViewAction.Unknown)
        {
            if (e.Node.Nodes.Count > 0)
            {
                if (!e.Node.Checked)
                {
                    this.CheckAllChildNodes(e.Node, e.Node.Checked);
                }
            }
        }

        if (e.Node.Parent != null)
        {
            TreeNode n = e.Node;
            while (n.Parent != null)
            {
                if (n.Checked)
                {
                    n.Parent.Checked = true;
                }
                n = n.Parent;
            }
        }

    }
 

В противном случае есть еще несколько документов о событии AfterCheck, которое действительно делает это