在Django中,当某些共享相同的日期时,按日期获取下一个/上一个对象

时间:2017-09-08 14:17:54

标签: django django-queryset

在Django中我有Letter模型:

class Letter(models.Model):
    letter_date = models.DateField(blank=False, null=False)

使用DateDetailView()查看单个字母时,我想显示" next"和"之前"链接。要获得下一个/上一个Letter我可以在其中一个视图方法中执行此操作(类似于获取next_letter):

try:
    previous_letter = self.model.objects.filter(
                    letter_date__lt=date).order_by('-letter_date')[:1].get()
except self.model.DoesNotExist:
    previous_letter = None

如果每天只有一个Letter,但是有些日子有多个字母,这个代码会在同一天跳过后续字母,这样可以正常工作。

如何确保下一个/上一个不会跳过字母?这听起来并不难,但我的大脑正在挣扎......

编辑:如果它有帮助,可以列出部分Letter个日期及其pk的日期:

  • 13325 1665-12-13
  • 13326 1666-01-31
  • 13327 1666-02-17
  • 13328 1666-02-17
  • 13329 1666-02-18

2 个答案:

答案 0 :(得分:1)

您需要向order_by添加第二个参数。同时还为filter方法添加了第二个参数。这样,Django将返回日期小于date的对象列表,并先按letter_date字段排序,然后按primary key排序。

previous_letter = self.model.objects.filter(
                letter_date__lt=date, pk__gt=pk).order_by('-letter_date', 'pk')

答案 1 :(得分:1)

尝试了几件事后......

我认为唯一/最好的方法是将另一个字段添加到Letter,在订购时用作辅助字段,以便同一天的字母始终采用相同的顺序:

class Letter(models.Model):
    letter_date = models.DateField(blank=False, null=False)
    order = models.PositiveSmallIntegerField(blank=False, null=False, default=0)

    class Meta:
        ordering = ['letter_date', 'order',]

然后在视图中,我们必须从同一天 a Letter查找较早的Letter。这是我的完整视图,以防它对任何人都有用:

from django.db.models import Q
from django.views.generic.dates import DateDetailView

from letters.models import Letter


class LetterDetailView(DateDetailView):
    model = Letter
    date_field = 'letter_date'
    year_format = '%Y'
    month_format = '%m'
    day_format = '%d'

    def get_context_data(self, **kwargs):
        context = super(LetterDetailView, self).get_context_data(**kwargs)
        extra_context = self.get_next_previous()
        context.update(extra_context)
        return context

    def get_next_previous(self):
        date = self.model.letter_date
        order = self.model.order

        try:
            previous_letter = self.model.objects \
                                .filter( \
                                    Q(letter_date__lte=date, order__lt=order) \
                                    | \
                                    Q(letter_date__lt=date) \
                                ) \
                                .order_by('-letter_date', '-order')[:1] \
                                .get()
        except self.model.DoesNotExist:
            previous_letter = None

        try:
            next_letter = self.model.objects \
                                .filter( \
                                    Q(letter_date__gte=date, order__gt=order) \
                                    | \
                                    Q(letter_date__gt=date) \
                                ) \
                                .order_by('letter_date', 'order')[:1] \
                                .get()
        except self.model.DoesNotExist:
            next_letter = None

        return {
            'previous_letter': previous_letter,
            'next_letter': next_letter,
        }

我不想添加其他字段,但我认为这是保持列表和下一个/上一个链接一致的唯一方法。