Django:怎么做这个查询?

时间:2015-07-30 16:38:12

标签: django django-models

我有3个型号:

  • 与ManyToMany Product模型相关联的模型Tag
  • 与ManyToMany Tag模型相关联的模型Product
  • 与OneToMany TagContent模型相关联的模型Tag(=一个内容仅链接到一个Tag,一个Tag可能包含一个或多个TagContent 1}})

模型TagContent适用于多语言:一个Product可能有多个Tag,但Tag通过TagContent显示在网页中:< / p>

class Tag(BaseModel):
    name = models.CharField(max_length=60, unique=True, default='')

class TagContent(BaseTranslatableModel):
    tag = models.ForeignKey(Tag, null=True, default=None)
    slug = models.SlugField(max_length=60, unique=True)
    locale = models.CharField(max_length=2)  # (e.g. "fr")

class Produit(BaseModel):
    name = models.CharField(max_length=60, unique=True)
    tags = models.ManyToManyField(Tag, related_name='produits')

这就是我想要做的事情:在我的主页面中,客户选择语言。因此,我将根据客户选择的语言显示所有产品。

在我的主视图中,我想显示所有产品和所有标签,以便用户可以点击标签,然后我会过滤产品。

问题是标签应该用当前语言翻译。这意味着我必须使用当前区域设置过滤TagContent,然后获取与Tag相关联的所有TagContent,然后获取与这些标记相关联的所有Product

这应该给出类似的东西(但它不起作用,因为外键在TagContent,这是阻止我的主要问题):

Product.objects.filter(tags__in=
    Tag.objects.filter(contents__in=
        TagContent.objects.filter(langue__locale__exact=locale)
    )
)

在模板模型中,我需要类似的东西:

        {% for p in products %}
            {% for tag. in p.tags.all %}
                {{ tag.name }}
            {% endfor %}
        {% endfor %}

换句话说,我想做这个SQL查询:

 SELECT tc.slug, tc.name
 FROM produit p
 JOIN produit_tag pt
     ON pt.produit_id = p.id
 JOIN tag t
     ON pt.tag_id = t.id
 JOIN tag_content tc
     ON tc.tag_id = t.id
 JOIN langue l
     ON tc.langue_id=l.id
 WHERE l.locale='fr'

- &GT; 2分钟写这个SQL,3小时我正在寻找解决方案。

3 个答案:

答案 0 :(得分:1)

您可以使用此orm查询来获取产品:

products = Product.objects.prefetch_related("Tag", "TagContent").
    filter(tags__tagcontent__locale="fr")

Django会像你手写的那样生成一个SQL。但是,一个SQL中的多个JOIN可能不是一个好主意,特别是如果连接的表非常大。考虑将查询分解为2可能会带来更好的性能(取决于您使用的数据库):

fr_tags = Tag.objects.filter(tagcontent__locale="fr")
products = Product.objects.filter(tags__in=fr_tags)

了解跨越关系的字段查找: https://docs.djangoproject.com/en/1.8/topics/db/queries/#lookups-that-span-relationships

答案 1 :(得分:0)

由于您已经拥有SQL查询,为什么不发送raw query。您只需将数据传递到模板即可。这将是类似的事情:

from django.db import connections

cursor = connection.cursor()
query = (""" SELECT tc.slug, tc.name
 FROM produit p
 JOIN produit_tag pt
     ON pt.produit_id = p.id
 JOIN tag t
     ON pt.tag_id = t.id
 JOIN tag_content tc
     ON tc.tag_id = t.id
 JOIN langue l
     ON tc.langue_id=l.id
 WHERE l.locale='fr' """)
cursor.execute(query)

data = []
for row in cursor.fetchall():
    slug = row[0]
    name = row[1]
    data_point = {'name': name, 'slug': slug}
    data.append(data_point)

答案 2 :(得分:0)

如果您没有使用PostgreSQL,这对您来说毫无用处,但我的前首席开发人员现在维护着django-pgviews项目。当您的SQL查询包含Django可能无法有效(或根本不能)执行的复杂连接时,它非常有用,您可以在自定义SQL视图中表示这些连接。你牺牲了Django的管理,但是你可以继续使用ORM来查询数据以便阅读。另请注意正在开发的django.contrib.postgres项目。