【问题标题】:Django. How can I get next post written by the same author? (filter get_next_by_FOO?)姜戈。如何获得同一作者的下一篇文章? (过滤get_next_by_FOO?)
【发布时间】:2016-04-28 12:29:05
【问题描述】:

我有一个有几个用户的博客。

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

我知道我可以这样做:

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

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

我可以通过特定作者以某种方式过滤此内容吗?

或者有没有更好的方法来获取下一篇/上一篇文章的网址?

【问题讨论】:

    标签: django django-templates django-views


    【解决方案1】:

    这是一个通用函数(来自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)
    

    【讨论】:

    • 非常感谢!不过我有一个小问题——“prev_by_author”函数总是返回创建的第一个帖子,而不是前一个。 “next_by_author”工作正常。你知道可能是什么问题吗?
    • 尝试在模型的 Meta 类中设置排序?
    • 是的!有用!太好了,谢谢你,太棒了=)
    猜你喜欢
    • 2021-03-24
    • 2021-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-26
    • 2013-03-31
    相关资源
    最近更新 更多