Как моделировать произвольно вложенные категории и подкатегории? - PullRequest
0 голосов
/ 26 сентября 2019

Я ищу эффективный способ моделирования категорий продуктов и произвольного количества вложенных подкатегорий в Django для целей электронной коммерции.То, что у меня сейчас есть, работает, но это становится проблемой, когда вы хотите выполнить запрос, чтобы получить все, скажем, книги, потому что вам нужно сначала рекурсивно просмотреть все подкатегории «Книги», а затем получить все книги из этих подкатегорий.

Допустим, у вас есть учебник по математике для начальной школы, он будет принадлежать:

Книги -> Учебники -> Начальная школа

... и получить все книгинужно было бы выполнить монстр-запрос, подобный этому:

>>> from products.models import Product, Category
>>> from django.db.models import Q
>>> c = Category(name='Books')
>>> c.save()
>>> c1 = Category(name='Textbooks', parent=c)
>>> c1.save()
>>> c2 = Category(name='Primary school', parent=c1)
>>> c2.save()
>>> p = Product(title='Math textbook', description='Math textbook for 4th grade', price=20, category=c2)
>>> p.save()
>>> Product.objects.filter(Q(category__name='Books') | Q(category__parent__name='Books') | Q(category__parent__parent__name='Books'))
<QuerySet [<Product: Product object (3)>]>

... что неэффективно, и вы не можете заранее знать, как будут вложены категории.

Вот какупрощенные модели выглядят так:

class Product(models.Model):
    title = models.CharField(max_length=200)
    description = models.TextField()
    price = models.DecimalField(decimal_places=2, max_digits=10)
    category = models.ForeignKey('Category', on_delete=models.CASCADE)


class Category(models.Model):
    parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.CASCADE)
    name = models.CharField(max_length=255)

1 Ответ

0 голосов
/ 26 сентября 2019

Одним из способов сделать это может быть добавление другого поля в модель категории с иерархическим именем категории, например Books.Textbooks.Primary_school, а затем поиск с использованием запроса, подобного Product.objects.filter(category__full_name__icontains='Books').Вы можете автоматизировать заполнение поля full_name, переопределив функцию сохранения.Таким образом, класс категории становится

class Category(models.Model):
    parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.CASCADE)
    name = models.CharField(max_length=255)
    full_name = models.TextField() # Can also set this to be CharField and choose max_length according to level of hierarchy expected.

    def save(self, *args, **kwargs):
        if self.parent is not None:
            self.full_name = self.parent.full_name + '.' + self.name  # Not a top level category
        else:
            self.full_name = self.name  # in case of a top level category
        super().save(*args, **kwargs)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...