Django MPTT — keep it simple stupid

в 21:28, , рубрики: Песочница

Есть монстр django-mptt, реализующий некую технику, позволяющую брать дерево или его часть одним запросом к базе.

А можно просто:

from django.db import models

class Category(models.Model):
    title = models.CharField(verbose_name=u'Заголовок', max_length=255)
    left = models.IntegerField(blank=True, null=True)
    right = models.IntegerField(blank=True, null=True)
    parent = models.ForeignKey(verbose_name=u'Родительская категория', to='self', blank=True, null=True, related_name='children')
    position = models.IntegerField(verbose_name=u'Позиция', blank=True, null=True)
    level = models.IntegerField(blank=True, null=True)
    published = models.BooleanField(verbose_name=u'Опубликован', default=True)

    def __unicode__(self):
        level = self.level if self.level else 1
        i = u'| ' if level > 1 else ''
        return (u'|--' * (level - 1)) + i + self.title

    class Meta:
        ordering = ('left',)

    def save(self, *args, **kwargs):
        super(Category, self).save(*args, **kwargs)
        self.set_mptt()

    def set_mptt(self, left=1, parent=None, level=1):
        for i in type(self).objects.filter(parent=parent).order_by('position'):
            obj, children_count = i, 0
            while obj.children.exists():
                for child in obj.children.all():
                    children_count += 1
                    obj = child
            data = {
                'level': level,
                'left': left,
                'right': left + (children_count * 2) + 1
            }
            type(self).objects.filter(id=i.id).update(**data)
            left = data['right'] + 1
            self.set_mptt(left=data['left'] + 1, parent=i.id, level=data['level'] + 1)

Что тут происходит?
Каждый раз при сохранении, всё дерево переиндексируется по технике MPTT.

Как достать дерево?

Category.objects.all()

Дерево мы отсортировали по 'position' ещё перед простановкой индексов:

type(self).objects.filter(parent=parent).order_by('position') 

Понимаю, что сниппеты — не формат для хабра, но очень не хочется филосовствовать на тему KISS, или расписывать про MPTT. Все давно всё поняли и знают. Просто, надеюсь, что это кому-то пригодится. Спасибо.

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js