Кластеризация категорий в моделях Django - PullRequest
0 голосов
/ 21 мая 2019

контекст: создание CMS

Я ищу эффективный способ представления тематической вложенности / зависимости статей в модели Django.Прямо сейчас, Категории определены следующим образом:

class Category(models.Model):
    parent        = models.ForeignKey('self', default=None, null=True, blank=True, related_name='nested_category', on_delete=models.CASCADE)
    name          = models.CharField(max_length=50, unique=True)
    nesting_level = models.IntegerField(default = 0, editable=False)

    def __init__(self, *args, **kwargs): 
        super(Category, self).__init__(*args, **kwargs)
        if self.parent != None:
            self.nesting_level = self.parent.nesting_level + 1
        elif self.parent == None:
            self.nesting_level = 0

    def __str__(self):                           
        full_path = [self.name.lower()]                                        
        k = self.parent                          

        while k is not None:
            full_path.append(k.name.lower())
            k = k.parent

        return '->'.join(full_path[::-1])

Это работает довольно хорошо.Каждый раз, когда добавляется категория, nesting_level рассчитывается на основе nesting_level родителя.Я вижу изменения в BDD (я знаю, что не нужно переопределять __init__ в Django, но я вернусь к этому вопросу позже).

Необходимость

Скажите, у меня есть следующееКатегория три:

Code--------Python---------Django
 [1]    |     [2]     |      [3]
        |             |----Functional_Programing
        |---Java               [5]
             [4]

При попадании в категорию Python , представление должно не только представлять Статьи в

  • code->python но также
  • code->python->django
  • code->python->functional_programing

, поскольку последние также связаны с питоном .При переходе по URL-адресу /browse/code->python/ представление будет выглядеть примерно так: articles = Article.objects.filter(category__in=[2, 3, 5])

Идея, которая не работает (и я не уверен, почему)

Поскольку категории не меняются довольно частоЯ подумал, что было бы неплохо, если бы представлял эти три структуры в самом BDD , чтобы легко извлечь список детей.Таблица будет выглядеть примерно так:

id | name                  | nesting_level | cluster | parent
1  | Code                  | 0             | 1,2,3,5 | None
2  | Python                | 1             | 2,3,5   | 1
3  | Django                | 2             | 3       | 2
4  | Java                  | 1             | 4       | 1
5  | Functional_programing | 3             | 5       | 2

Класс Категория , слегка измененный:

class Category(models.Model):
    parent        = models.ForeignKey('self', default=None, null=True, blank=True, related_name='nested_category', on_delete=models.CASCADE)
    name          = models.CharField(max_length=50, unique=True)
    nesting_level = models.IntegerField(default = 0, editable=False)
    cluster       = models.CharField(default = "", max_length=20, editable=False)

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

        self.cluster = str(self.id)
        if self.parent != None:
            self.nesting_level = self.parent.nesting_level + 1
            self.parent.cluster = "{},{}".format(self.parent.cluster,self.id)
        elif self.parent == None:
            self.nesting_level = 0

Кажется, работает, когда я print, но изменения делаюткажется, не добавляются в BDD (на этой ранней стадии разработки: SLQlite ).Я прочитал, что __init__ не должно быть переопределено в Django по связанным причинам сигнала , поэтому я также попытался переопределить save вместо:

def save(self, *args, **kwargs):
        self.cluster = str(self.id)
        if self.parent != None:
            self.nesting_level = self.parent.nesting_level + 1
            self.parent.cluster = "{},{}".format(self.parent.cluster,self.id)
        elif self.parent == None:
            self.nesting_level = 0
        super(Category, self).save(*args, **kwargs)

, который тоже не работает, нона этот раз, потому что self.id=None(<class 'NoneType'>).

Я начинаю чувствовать себя немного потерянным в тонкостях этого ORM.Поскольку, вероятно, есть более простые способы достижения того, что я ищу, но мне также интересно понять, почему мой подход не работает, приветствуются всевозможные советы .

...