每个类别的最后 N 个帖子 SQL 到 ORM

Last N posts per category SQL to ORM

我正在开始我的第一个 Django 博客应用程序 [在完成 Django 官方教程和 Django Girls 教程之后]。我在思考 Django ORM 时遇到了一些麻烦。我有一个有效的 SQL 查询,但我觉得它效率很低,我宁愿在继续之前学习正确的方法。

Post.objects.raw(('SELECT * FROM (SELECT id, category, body, slug, author, title, 
published, row_number() OVER (PARTITION BY category) as rownum FROM post) tmp 
WHERE rownum < 5'))

基本上我想显示每个 post 类别的最后 5 行。上面的代码已经在工作了,问题是当我在我的模板中循环遍历每个 post 时,当 Post 的 get_absolute_url 正在调用方法。我使用 Django 的 {% url %} 标记修复了此问题,但仍有 7 个额外的查询 运行,我想将其限制为最多 2-3 个。

我有这样一个模型:

class Post(models.Model):
    title = models.CharField(max_length=250)
    category = models.CharField(max_length=30, choices=CATEGORY_CHOICES)
    tags = TaggableManager()
    slug = models.SlugField(max_length=250, unique_for_date='published')
    author = models.CharField(max_length=50)
    body = HTMLField('body')
    published = models.DateTimeField(default=timezone.now)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    status = models.CharField(max_length=10, choices=STATUS_CHOICES,
                             default='draft')

    class Meta:
        ordering = ('-published',)
        db_table = 'post'

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('post_detail', args=[self.category, self.slug])

我尝试了几个小时来通过 ORM 让它工作,但无法让它工作。我最终用原始 SQL 完成了它,但我不知道 20 多个额外的查询将是 运行。主要目标是显示按发布日期排序的每个类别的最后 5 post 秒。我正在使用 PostgreSQL.

我想你想要最后 3 个帖子,如果是这样你可以切片

def mayview(request):
    last_posts = Post.objects.all().order_by('-created_at')[:3]  # list of last posts
    return render(request, 'path/to/template', {'last_posts': last_posts})

在您的模板中使用 for 循环解压列表:

{%for post in last_posts%}

<h1>{{post.title}}</h1>
<p>{{post.body}}</p>
<small>{{post.created_by}}</small>

{% endfor %}

您的解决方案即将完成。

from django.db.models.expressions import RawSQL

qs = Post.objects.filter(pk__in=RawSQL(
    'SELECT id FROM '
    '  (SELECT id, '
    '    row_number() OVER (PARTITION BY category ORDER BY published DESC) as rownum '
    '   FROM post) tmp '
    'WHERE rownum < 5',
    []
)).order_by('category', '-published')

Window functions 可用于 Django 2.0 而不是 RawSQL。 (应该在2.0发布后更新)