Django的。如何获得同一作者撰写的下一篇文章? (过滤get_next_by_FOO?)

问题描述 投票:2回答:1

我有几个用户的博客。

我想在帖子页面添加“下一篇文章”和“上一篇文章”按钮,我希望它们链接到同一作者撰写的下一篇/上一篇文章。

我知道我可以这样做:

<a href="/post/{{post.get_next_by_pub_date.slug}}">Next Post</a>

但这将链接到任何作者撰写的下一篇文章。

我可以以某种方式过滤特定作者吗?

或者有更好的方法来获取下一个/上一个帖子的网址?

django django-templates django-views
1个回答
2
投票

这是一个通用函数(来自django-baseclasses),可以满足您的需求。它从自定义查询集中获取下一个或上一个项目(在您的情况下对作者进行过滤),并尊重模型Meta类中的顺序(您需要一个明确的Meta.ordering才能工作)

from functools import reduce
from django.db import models

def get_model_attr(instance, attr):
    """Example usage: get_model_attr(instance, 'category__slug')"""
    for field in attr.split('__'):
        instance = getattr(instance, field)
    return instance


def next_or_prev_in_order(instance, prev=False, qs=None, loop=False):
    """Get the next (or previous with prev=True) item for instance, from the
       given queryset (which is assumed to contain instance) respecting
       queryset ordering. If loop is True, return the first/last item when the
       end/start is reached. """

    if not qs:
        qs = instance.__class__.objects
    if prev:
        qs = qs.reverse()
        lookup = 'lt'
    else:
        lookup = 'gt'

    q_list = []
    prev_fields = []
    if qs.model._meta.ordering:
        ordering = list(qs.model._meta.ordering)
    else:
        ordering = []

    for field in (ordering + ['pk']):
        if field[0] == '-':
            this_lookup = (lookup == 'gt' and 'lt' or 'gt')
            field = field[1:]
        else:
            this_lookup = lookup
        q_kwargs = dict([(f, get_model_attr(instance, f))
                         for f in prev_fields])
        key = "%s__%s" % (field, this_lookup)
        q_kwargs[key] = get_model_attr(instance, field)
        q_list.append(models.Q(**q_kwargs))
        prev_fields.append(field)
    try:
        return qs.filter(reduce(models.Q.__or__, q_list))[0]
    except IndexError:
        length = qs.count()
        if loop and length > 1:
            # queryset is reversed above if prev
            return qs[0]
    return None

像这样使用它:

class Post(models.Model):
    ...

    def prev_by_author(self):
        qs = Post.objects.filter(author=self.author)
        return next_or_prev_in_order(self, True, qs)

    def next_by_author(self):
        qs = Post.objects.filter(author=self.author)
        return next_or_prev_in_order(self, False, qs)
© www.soinside.com 2019 - 2024. All rights reserved.