如何在 Django 中执行此连接查询

Posted

技术标签:

【中文标题】如何在 Django 中执行此连接查询【英文标题】:How to do this join query in Django 【发布时间】:2010-10-26 01:06:47 【问题描述】:

在 Django 中,我有两个模型:

class Product(models.Model):
    name = models.CharField(max_length = 50)
    categories = models.ManyToManyField(Category)

class ProductRank(models.Model):
    product = models.ForeignKey(Product)
    rank = models.IntegerField(default = 0)

我将排名放到一个单独的表中,因为页面的每个视图都会导致排名发生变化,而且我担心所有这些写入操作会使我的其他(主要是读取)查询变慢。

我从一个简单的查询中收集了Products 的列表:

cat = Category.objects.get(pk = 1)
products = Product.objects.filter(categories = cat)

我现在想获得这些产品的所有排名。我宁愿一次性完成所有操作(使用 SQL 连接),并且想知道如何使用 Django 的查询机制来表达。

在 Django 中执行此操作的正确方法是什么?

【问题讨论】:

听起来像是过早的优化。您是否有任何分析器证据表明“所有这些写入都会使我的其他查询变慢”?或者当您需要阅读排名时,这种效果比额外 JOIN 的减速更糟糕?先用简单的方法写出来,在证明有必要之前不要优化。 【参考方案1】:

对于 Django 2.1 来自文档

此示例检索名称为“Beatles Blog”的 Blog 的所有 Entry 对象:

 Entry.objects.filter(blog__name='Beatles Blog')

文档网址 https://docs.djangoproject.com/en/2.1/topics/db/queries/

【讨论】:

【参考方案2】:

这可以在 Django 中完成,但您需要稍微不同地重构模型:

class Product(models.Model):
    name = models.CharField(max_length=50)
    product_rank = models.OneToOneField('ProductRank')

class ProductRank(models.Model):
    rank = models.IntegerField(default=0)

现在,在获取 Product 对象时,您可以使用 select_related() 方法在一个查询中遵循一对一关系:

Product.objects.filter([...]).select_related()

这将产生一个使用连接获取产品排名的查询:

SELECT "example_product"."id", "example_product"."name", "example_product"."product_rank_id", "example_productrank"."id", "example_productrank"."rank" FROM "example_product" INNER JOIN "example_productrank" ON ("example_product"."product_rank_id" = "example_productrank"."id")

我不得不将 Product 和 ProductRank 之间的关系字段移动到 Product 模型,因为它看起来 select_related() 只在一个方向上遵循外键。

【讨论】:

哈哈。我今天只是在阅读 OneToOneField 上的文档,想知道它有什么用处!感谢您提供的重要信息。【参考方案3】:

我没有检查但是:

products = Product.objects.filter(categories__pk=1).select_related()

应该抓取每个实例。

【讨论】:

【参考方案4】:

添加对 QuerySet 的 select_related() 方法的调用,虽然我不肯定会在两个方向上获取引用,但这是最有可能的答案。

【讨论】:

以上是关于如何在 Django 中执行此连接查询的主要内容,如果未能解决你的问题,请参考以下文章

如何过滤 Django 查询的连接表,然后在一个查询中迭代连接表?

Django 按顺序连接两个查询集

Django 内连接查询集

我将如何将这些多个连接作为 Django 查询集进行?

如何通过 django 模型查询创建与组的左连接

django中的完全外连接