Django:来自非嵌套模型的嵌套查询

标签 django django-models

我试图找出从一组非嵌套模型派生嵌套菜单的最佳方法。给定这样的布局:

class Beverage(models.Model):
   country = models.ForeignKey(Country,null=True,blank=True)    
   region = models.ForeignKey(Region,null=True,blank=True)
   subregion = models.ForeignKey(SubRegion,null=True,blank=True) 
   in_stock = models.BooleanField()
   ...

生成的菜单将类似于:
France
    Region 1
        Subregion 1
        Subregion 2
    Region 2
        Subregion 3
        Subregion 4
Spain
    ....

如果菜单中没有无库存的饮料,则菜单中不应出现任何国家、地区或次区域。因为一个子区域总是属于一个区域而一个区域总是属于一个国家,所以我最初的方法是嵌套模型本身,并且只将 SubRegion 放在 Beverage 上。区域和国家将始终被饮料的子区域所知晓。不幸的是,现实世界中存在太多异常(exception)情况,无法实现这一点 - 有地区但没有子地区的葡萄酒等。所以我将布局按上述方式展平。

现在的问题是如何从这个模型布局中导出菜单。看起来深度嵌套的查询集列表将是要走的路,但这在计算上似乎很昂贵,并且在代码方面很复杂。有更干净的方法吗?

最佳答案

我过去用来解决类似问题的一个过程是通过一次查询选择所有项目,然后是基于国家、地区、子地区的订单。然后您循环查询结果并维护指向您看到的国家和地区的最后一个 id 的变量。如果饮料上的下一个国家/地区 ID 与上一个 ID 不匹配,则保存旧列表并开始一个新列表。这里有一些非常粗糙/凌乱的pythoncode来解释这个想法:

beverages = Beverage.objects.order_by('country', 'region', 'subregion')
last_country = -1
menu = []
country_obj = None
for beverage in beverages:
    if beverage.country_id != last_country:
        if country_obj is not None:
            if region_obj is not None:
                if subregion_obj is not None:
                    region_obj['children'].append(subregion_obj)
                country_obj['children'].append(region_obj)
            menu.append(country_obj)
        country_obj = {'name': beverage.country.name, 'children': []}
        last_country = beverage.country_id
        last_region = -1
        region_obj = None
        last_subregion = -1
        subregion_obj = None
    if beverage.region is None:
        country_obj['children'].append(beverage)    
    else:
        if beverage.region_id != last_region:
            if region_obj is not None:
                if subregion_obj is not None:
                    region_obj['children'].append(subregion_obj)
                country_obj['children'].append(region_obj)
            region_obj = {'name': beverage.region.name, 'children': []}
            last_region = beverage.region_id
            last_subregion = -1
            subregion_obj = None
        if beverage.subregion is None:
            region_obj['children'].append(beverage)
        else:
            if beverage.subregion_id != last_subregion:
                if subregion_obj is not None:
                    region_obj['children'].append(subregion_obj)
                subregion_obj = {'name': beverage.subregion.name, 'children': []}
                last_subregion = beverage.subregion_id
            subregion_obj['children'].append(beverage)
if beverage.subregion is not None:
    region_obj['children'].append(subregion_obj)
if beverage.region is not None:
    country_obj['children'].append(region_obj)
menu.append(country_obj)

正如您可能知道的那样,每个级别都有相同的逻辑:检查 id 是否已更改,是否已附加旧的 x_obj 并开始一个新的。最后五行是处理最后一杯饮料,因为您总是在当前迭代期间保存前一项(并且最后一项没有下一次迭代)。这在边缘真的很粗糙,但这是我一直使用的过程,只需要一个查询。

当我终于开始运行它时,我进行了编辑以修复我发现的一些错误。它似乎适用于我的简单测试用例。

关于Django:来自非嵌套模型的嵌套查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1373772/

相关文章:

python - Django 模板标签循环字典变量

Django南: Re-run first migration

javascript - Django 表单和 javascript 或者其他一些方法可以做到同样的事情

Django 在删除时创建 "sentinel"用户

django - 在 pytest-factoryboy 中参数化具有多表继承的 Django 模型的属性

Django 。 Google 地点自动填写地址表单

python - 在 django 上使用 mako 时如何处理国际化,

python - Pillow 安装错误 : command 'gcc' failed with exit status 1

python - Django:检索用户模型时自动选择相关模型UserProfile

python - Django媒体文件路径不正确,缺少目录