【问题标题】:Django select_related() and GenericForeignKeyDjango select_related() 和 GenericForeignKey
【发布时间】:2011-07-20 00:13:28
【问题描述】:

我有这样的模型:

class Comment(models.Model):
    text = models.TextField(max_length = 250, blank = False)
    author = models.ForeignKey(User)
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')

class Product(models.Model):
    name = models.CharField(max_length = 40)
    comments = generic.GenericRelation(Comment)

在这个模板中,我展示了所有产品的最新 5 cmets:

<ul>
    {% for comment in last_comments %}
    <li><a href="/user/{{ comment.author }}/">{{ comment.author }}</a> on <a href="/product/{{ comment.content_object.name }}/">{{ comment.content_object }}</a>
    <br>{{ comment.text }}</li>
    {% endfor %}
</ul>

如果我得到 last_commentslast_comments = Comment.objects.all().order_by('-id')[:5] django 调试工具栏说执行了 25 次查询。

如果我得到 last_commentslast_comments = Comment.objects.select_related().all().order_by('-id')[:5] django 调试工具栏说执行了 20 次查询。

但是为什么select_related 也不选择相关的 content_object 呢?在 django 调试工具栏中,我看到了 5 个获取产品的查询。而且肯定是{{ comment.content_object }}的结果

可能是因为我在Comment模型中使用了GenericForeignKey

你有什么想法吗?

【问题讨论】:

  • 好吧,您实际上可以使用from django.db import connection 查看查询,然后显示connection.queries 的内容。我认为这会让你更好地了解到底发生了什么。
  • 为什么? django 调试工具栏 SQL 查看器还不够好吗?
  • 好吧,你的帖子听起来你不是 100% 确定 GenericForeignKey 是原因(我希望它肯定至少对大多数查询负责),所以在查看实际的 SQL 我认为这一切都会很清楚。它还可以帮助其他人提出解决方案。使用通用关系链接什么样的对象?它们之间真的有那么大的不同吗?
  • 我确定是现在的原因。看这个问题:stackoverflow.com/questions/2939552/…

标签: python django


【解决方案1】:

您可以尝试重构您的数据库,使其看起来像这样:

class Comment(models.Model):
    ...
    content_object = models.ForeignKey(Content)

class Content(models.Model):
    text = models.CharField(max_length=123)

class SomeSpecificContent(models.Model):
    ...
    content = models.ForeignKey(Content)

class OtherSpecificContent(models.Model):
    ...
    content = models.ForeignKey(Content)

在 Django 的情况下,这实际上与以下架构非常相似:

class Comment(models.Model):
    ...
    content_object = models.ForeignKey(Content)

class Content(models.Model):
    text = models.TextField()

class SomeSpecificContent(Content):
    ...

class OtherSpecificContent(Content):
    ...

因为这基本上是在 Django 中处理继承的方式。后者可能不太灵活,并且在 SomeSpecificContent 和 OtherSpecificContent 实际上代表完全不同的概念的情况下可能有点难以理解。

另一方面,泛型关系无法准确有效地处理,因为它们可以链接到您希望它们链接的任何表。因此,如果您有一个包含 5 个对象的列表,则可能会发生每个对象都与不同类型的实体相关的情况。不确定 Django 如何处理 100 个对象与 5 种实​​体相关的情况。它实际上会生成 5+1 个查询吗?

【讨论】:

    猜你喜欢
    • 2015-02-02
    • 2012-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-04
    • 1970-01-01
    • 1970-01-01
    • 2020-03-21
    • 1970-01-01
    相关资源
    最近更新 更多