繁体   English   中英

Django ORM,如何将查询集“变基”到相关的 model

[英]Django ORM, how to "rebase" a QuerySet to a related model

使用下面简化玩具示例中描述的数据库 model,我们试图获取用于特定Product的 EAV 属性列表。

下面“操作”部分中的示例源代码可用于此目的; 然而,我们觉得该语句过于冗长:我们只需要template_attribute表的列,但值 arguments 需要维护从原始Product model 开始的完全限定路径。请参见下面的代码:

# Getting the `id` columns from multiple-orders of related models:
attribute_set = template. values(
  "id",                              # the base model, Product
  "template__id",                    # the related model, Template
  "template__templateattribute__id"  # the second related model, TemplateAttribute
)

因此,我们想知道是否有一种方法可以直接从包含 model 的列中引用列,例如templateattribute__id或更好的id ,而不是template__templateattribute__id

我们是 Django ORM 的新手,感谢任何提示或建议。

动作:

template = Product.active_objects.filter(id='xxx').select_related('template')
attribute_set = template. values("id", "template__id", "template__templateattribute__id")

for i, attr in enumerate(attribute_set):
    print("{:03}: {}".format(i, attr))
# Output:
# 000: {'id': xxx, 'template__id': xxxx, 'template__templateattribute__id': xxxxx}
# 001: {'id': xxx, 'template__id': xxxx, 'template__templateattribute__id': xxxxx}
# 002: {'id': xxx, 'template__id': xxxx, 'template__templateattribute__id': xxxxx}
# ...

型号:

# Simplified toy example

class Product(models.Model):
    product_template = models.ForeignKey(Template)
    sku = models.CharField(max_length=100)
    ...

class Template(models.Model):
    base_sku = models.CharField(max_length=100)
    ...

class TemplateAttribute(models.Model):
    product_template = models.ForeignKey(Template)
    attribute = models.ForeignKey(eav_models.Attribute)
    ...

# From the open-source Django EAV library
# imported as `eav_models`
# 
class Attribute(models.Model):
    name = models.CharField(_(u"name"), max_length=100,
                            help_text=_(u"User-friendly attribute name"))
    ...
    slug = EavSlugField(_(u"slug"), max_length=50, db_index=True,
                          help_text=_(u"Short unique attribute label"))
    ...

也许使用带有注释或别名的管理器会有所帮助?

您可以尝试通过在管理器的构造期间为每个键动态添加注释来尝试添加更多魔法,但实际上此时您正在编写本应在 EAV 本身中的代码。

我会警告您,将属性名称及其值放在表中而不是只有 model 字段(和数据库中的列)将是一场艰苦的战斗,而且您已经发现您的图书馆没有为您处理事情的区域。

from django.db import models
from django.db.models import F


class ProductManager(models.Manager):
    def get_queryset(self):
        qs = super().get_queryset() \
            .annotate(
            my_attribute_key=F('template__templateattribute__id')
        )
        return qs

此外,我们还通过定义基本路径找到了解决方法:

base = "template__templateattribute"

所以,而不是

attribute_set = template. Values("template__templateattribute__id")

,我们可以做到以下几点:

attribute_set = template. Values(base+"__id")

不过,这只是一种非正式的解决方法。 更好的方法仍然是使用 Manager class

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM