两层菜单:我应该进行原始 SQL 查询吗?
Two-tier menu: shall I make a raw SQL query?
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
我们可以在这里看到一个两层菜单。
我无法想象从数据库中 select 数据的最佳方式是什么。
当然,我也会使用模板。我将对数据库进行多次查询,然后使用循环。并将其全部缓存在模板中。
换句话说:我打算在这里组织一段非常低效的代码并使用缓存隐藏它。
或者我也在考虑自定义 SQL-query,我一点也不喜欢。
在这种情况下,您能告诉我从数据库中获取 select 数据的最佳方法是什么吗?这个 meny 的模板草稿可能是什么样子的?
您可以使用 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_*
更改为您正在使用的实际相关名称。
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
我们可以在这里看到一个两层菜单。
我无法想象从数据库中 select 数据的最佳方式是什么。
当然,我也会使用模板。我将对数据库进行多次查询,然后使用循环。并将其全部缓存在模板中。
换句话说:我打算在这里组织一段非常低效的代码并使用缓存隐藏它。
或者我也在考虑自定义 SQL-query,我一点也不喜欢。
在这种情况下,您能告诉我从数据库中获取 select 数据的最佳方法是什么吗?这个 meny 的模板草稿可能是什么样子的?
您可以使用 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_*
更改为您正在使用的实际相关名称。