【问题标题】:Ordering a Django QuerySet by a datetime's month/day?按日期时间的月/日订购 Django QuerySet?
【发布时间】:2011-05-13 06:46:00
【问题描述】:

我有一个人员列表,每个人都有一个生日,可以预见地存储在DateField 中。我正在尝试创建这些人的列表——按他们出生的排序(不考虑年份)——有一种“谁的生日是即将到来”显示。

我似乎无法通过此人的 datetime.month 值订购 QuerySet。有什么方法可以做到这一点而不必诉诸list()

提前致谢,如果问题需要澄清,请告诉我。

【问题讨论】:

    标签: django datetime sql-order-by django-queryset


    【解决方案1】:

    您可以使用QuerySet.extra() 定义月份字段并按其排序:

    SomeModel.objects.extra(select={'birthmonth': 'MONTH(birthdate)'},
        order_by=['birthmonth']) 
    

    【讨论】:

    • 感谢您的快速回答!只是想澄清那些使用 PostgreSQL 将 MONTH(birthdate) 替换为 EXTRACT(MONTH FROM birthdate) 的人。
    • 正确的方法名是额外的
    • 尽管我很喜欢这个答案,但 QuerySet.extra() 方法似乎在砧板上,最终将被弃用。 django 文档指出,“将此方法作为最后的手段”和“这是一个旧 API,我们打算在未来某个时候弃用。”
    【解决方案2】:

    较新版本的 django 可以查找 DateFields 和 DateTimeFields。 https://docs.djangoproject.com/en/1.11/ref/models/database-functions/#extract

    MyModel.objects.order_by('birthday__month', 'birthday__day')

    【讨论】:

      【解决方案3】:

      我使用 django 1.10.8 测试过

      from django.db.models.functions import Extract
      from your_project.your_app.models import Person
      
      
      CHOICE_MONTH = (
          (None, '--'),
          (1, 1),
          (2, 2),
          (3, 3),
          (4, 4),
          (5, 5),
          (6, 6),
          (7, 7),
          (8, 8),
          (9, 9),
          (10, 10),
          (11, 11),
          (12, 12),
      )
      
      class PersonSearchForm(forms.Form):
      
          name = forms.CharField(label=u'name', required=False)
          month = forms.ChoiceField(label='month', choices=CHOICE_MONTH, required=False)
      
          def __init__(self, *args, **kwargs):
              self.corporation = kwargs.pop('corporation', None)
              super(PersonSearchForm, self).__init__(*args, **kwargs)
      
          def get_result_queryset(self):
              q = Q(corporation=self.corporation)
              if self.is_valid():
                  name = self.cleaned_data['name']
                  if name:
                      q = q & Q(name__icontains=name)
                  month = self.cleaned_data['month']
                  if month:
                      q = q & Q(month=int(month))
      
              return Person.objects.annotate(month=Extract('birthday', 'month'),
                                             day=Extract('birthday', 'day')).filter(q).order_by('month', 'day')
      

      【讨论】:

      • 请考虑为您的回答添加一些解释。
      【解决方案4】:

      对于 django >= 2.1

      您可以使用 DateField 上的月份和日期查找名称对 QuerySet 进行排序。

      SomeModel.objects.order_by('birth_date__month', 'birth_date__day')
      

      对于 django >= 1.10

      使用数据库函数Extract 通过annotate 方法生成额外的月份和日期列,然后order_by 这些列您可以仅按生日对QuerySet 进行排序。

      from django.db.models.functions import Extract
      
      SomeModel.objects.annotate(
          birth_date__month = Extract('birth_date', 'month'),
          birth_date__day = Extract('birth_date', 'day')
      ).order_by('birth_date__month', 'birth_date__day')
      

      对于较旧的 django 版本

      对于较旧的django 版本,您可以使用QuerySet.extra() 执行相同操作,但您必须编写数据库特定查询

      • MySQL

        SomeModel.objects.extra(select={
                'birth_date_month': 'MONTH(birth_date)',
                'birth_date_day': 'DAY(birth_date)'
            },
            order_by=['birth_date_month','birth_date_day']
        )
        
      • PostgreSQL

        SomeModel.objects.extra(select={
                'birth_date_month': 'EXTRACT(MONTH FROM birth_date)',
                'birth_date_day': 'EXTRACT(DAY FROM birth_date)'
            },
            order_by=['birth_date_month','birth_date_day']
        )
        
      • SQlite

        SomeModel.objects.extra(select={
                'birth_date_month': 'strftime("%m", birth_date)',
                'birth_date_day': 'strftime("%d", birth_date)'
            },
            order_by=['birth_date_month','birth_date_day']
        )
        

      【讨论】:

        【解决方案5】:

        Post.objects.all().order_by('date_posted__minute').reverse() 其中 date_posted 是您在 Post 模型中使用的属性。

        Post 只是一个示例模型

        【讨论】:

        • 您好 Janaki,感谢您的发帖!在您的答案中添加更多详细信息并使用他们使用的术语(出生月份/日期,而不是 date_posted),将帮助发布者理解您的答案,而无需他们提出后续问题。看看这个问题的其他答案,以了解需要什么。它也有助于format your code
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-07-21
        • 2018-09-29
        • 1970-01-01
        • 1970-01-01
        • 2014-03-12
        • 1970-01-01
        • 2014-03-22
        相关资源
        最近更新 更多