【问题标题】:Two-tier menu: shall I make a raw SQL query?两层菜单:我应该进行原始 SQL 查询吗?
【发布时间】:2021-10-26 16:10:40
【问题描述】:

Django 3.2.6

class Menu(NameUniqueMixin,
           ArchivedMixin,
           models.Model):
    TYPE_CHOICES = [
        (MenuTypes.TOP.value, MenuTypes.TOP.value),
    ]

    type = models.CharField(max_length=10, choices=TYPE_CHOICES)


class MenuLevelOne(NameUniqueMixin,
                   ArchivedMixin,
                   models.Model):
    menu = models.ForeignKey(Menu,
                             on_delete=models.PROTECT,
                             related_name="%(app_label)s_%(class)s_related",
                             related_query_name="%(app_label)s_%(class)ss", )

    html = models.TextField(default="",
                            blank=False,
                            null=False)
    rank = models.PositiveIntegerField(default=0,
                                       null=False,
                                       unique=True,
                                       db_index=True, )


class MenuLevelTwo(NameUniqueMixin,
                   ArchivedMixin,
                   models.Model):
    level_one = models.ForeignKey(MenuLevelOne,
                                  on_delete=models.PROTECT,
                                  related_name="%(app_label)s_%(class)s_related",
                                  related_query_name="%(app_label)s_%(class)ss", )
    html = models.TextField(default="",
                            blank=False,
                            null=False)
    rank = models.PositiveIntegerField(default=0,
                                       null=False,
                                       db_index=True, )

我想做一个树状菜单。 像这样:

os
  \windows
  \linux
hardware
  \motherboards
  \sound cards

我们可以在这里看到一个两层菜单。

我无法想象从数据库中选择数据的最佳方式是什么。

当然,我也会使用模板。我将对数据库进行几次查询,然后使用循环。并将其全部缓存在模板中。

换句话说:我打算在这里组织一段效率极低的代码并使用缓存隐藏它。

或者我也在考虑自定义 SQL 查询,我一点也不喜欢。

你能告诉我在这种情况下从数据库中选择数据的最糟糕的方法是什么吗?以及这些人的粗略模板可能是什么样的?

【问题讨论】:

    标签: python django django-models django-queryset


    【解决方案1】:

    您可以使用prefetch_related 获取所有Menu 对象,还可以获取映射到其上方每个菜单的所有相关子菜单。

    此外,您可以使用 Prefetch 和查询集来指定对象的顺序,在这种情况下,我假设将基于 rank,所以:

    menu = Menu.objects.all().prefetch_related(
        Prefetch('app_label_menulevelone_related', queryset=MenuLevelOne.objects.order_by('rank'),
        Pefetch('app_label_menulevelone_related__app_label_menuleveltwo_related', queryset=MenuLevelTwo.objects.order_by('rank'),
    )
    
    #  Would work the same in the templates
    for m in menu:
        print(m.type)
        for one in m.app_label_menulevelone_related.all():
            print(one.html)
            for two in one.app_label_menuleveltwo_related.all():
                print(two.html)
    

    这将总共进行 3 个查询,一个针对 Menu,一个针对 MenuLevelOne,一个针对 MenuLevelTwo。只需将app_label_* 更改为您使用的实际相关名称即可。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-21
      • 2012-03-16
      相关资源
      最近更新 更多