Django的select_related()和GenericForeignKey
我有这样的模型:
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条评论:
<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_comments = Comment.objects.all().order_by('-id')[:5]
来获取 last_comments
,django调试工具显示执行了25个查询。
如果我用 last_comments = Comment.objects.select_related().all().order_by('-id')[:5]
来获取 last_comments
,django调试工具显示执行了20个查询。
但是为什么 select_related
不能同时选择相关的内容对象呢?在django调试工具中,我看到获取产品的查询有5个。这显然是因为 {{ comment.content_object }}
的结果。
可能的原因是因为我在 Comment
模型中使用了GenericForeignKey。
你有什么想法吗?
1 个回答
-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实际上代表完全不同的概念,理解起来可能会有点困难。
另一方面,通用关系(Generic relations)之所以处理起来不太高效,就是因为它们可以和你想要的任何表连接。所以如果你有5个对象,可能每个对象都和不同类型的实体有关。我不太确定Django是怎么处理100个对象和5种实体之间的关系的。它会生成5+1个查询吗?