Django:如何以最佳方式建立关系和查询?

时间:2014-10-18 16:17:34

标签: django django-models

我是Django的新手,我在使用相关对象方面遇到了困难。在SQL方面这么简单似乎在这里非常棘手。

我有一个简单的数据库,如下所示:

from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType
from django.db import models

class Language(models.Model):
  code = models.CharField(max_length = 2)
  name = models.CharField(max_length = 20)

class Translation(models.Model):
  content_type = models.ForeignKey(ContentType)
  object_id = models.PositiveIntegerField()
  content_object = GenericForeignKey('content_type', 'object_id')

  language = models.ForeignKey(Language)
  title = models.TextField()
  text = models.TextField()

class Article(models.Model):
  pub_date = models.DateTimeField(verbose_name = "Publication date")
  visible = models.BooleanField(default = False)
  translations = GenericRelation(Translation)

这基本上是my previous question的后续行动。感谢Andrea Corbellini,上述模型看起来非常简洁明了。

现在我想在网页上显示这些文章。有一种当前语言,我只需要选择1)可见的文章和2)翻译当前语言。在SQL中,这意味着连接多个表并在单个查询中过滤它们。

如何在Django中做到这一点?这个问题实际上包括两个问题:如何进行快速查询以及如何将结果传递给模板。

我现在所做的是首先按可见进行过滤,然后按 pub_date 进行排序,然后遍历查询集,挑选具有正确翻译的文章,最后复制他们的字段进入上下文,因为模板引擎似乎并不了解如何访问相关对象。这是代码;它看起来很尴尬:

  articles = Article.objects.filter(visible = True).order_by('-pub_date')
  recent_news = []
  for article in articles:
    content = article.content(translation.get_language())
    if not content.exists():
      continue
    content = content[0]
    recent_news.append({
      'pub_date': article.pub_date,
      'title': content.title,
      'abstract': content.text,
      'text': content.text
    })
  context = { 'recent_news_list': recent_news }

这里有什么帮助就像一个元模型'或者某些中间件可以执行某些工作并缓存结果,因此请求某些语言的文章需要单个查询。但这是一个好方法吗?

1 个答案:

答案 0 :(得分:1)

由于您需要发送到模板的所有信息都在翻译模型中,我会对该模型进行查询,并将其发送到模板。您在文章模型中唯一需要的是visible字段,因此您可以对其进行过滤:

article = ContentType.objects.get_for_model(Article)
article_ids = Article.objects.filter(visible=True).values_list('id')
translations = Translation.objects.filter(content_type=article, object_id__in=article_ids)
context = {'recent_news_list: translations}

这只是三个查询:一个用于获取ContentType(虽然这可能会自动缓存),一个用于获取翻译,一个用于获取文章(而Django可能确实做第三个作为第二个子查询)。

但是,它总是会稍微复杂一点;这是您使用通用关系所付出的代价。我知道你的另一个问题确实有多种与翻译有关的类型,但是如果你能在没有做到这一点的情况下逃脱,那确实会更简单。