Заказ Django QuerySet по месяцу/дню даты и времени?

У меня есть список людей, у каждого из которых есть дата рождения, которая предсказуемо хранится в файле DateField. Я пытаюсь создать список этих людей, отсортированный по месяцу и дню их рождения (без учета года), чтобы было что-то вроде «у кого день рождения появится".

Кажется, я не могу заказать QuerySet по значению человека datetime.month. Есть ли способ сделать это, не прибегая к принуждению к list()?

Заранее спасибо и, пожалуйста, дайте мне знать, если вопрос нуждается в разъяснении.


person Bryan Veloso    schedule 21.11.2010    source источник


Ответы (5)


Вы можете использовать QuerySet.extra() для определения поля месяца и сортировки по нему:

SomeModel.objects.extra(select={'birthmonth': 'MONTH(birthdate)'},
    order_by=['birthmonth']) 
person Ignacio Vazquez-Abrams    schedule 21.11.2010
comment
Спасибо за быстрый ответ! Просто хотел уточнить для тех, кто использует PostgreSQL, чтобы заменить MONTH(birthdate) на EXTRACT(MONTH FROM birthdate). - person Bryan Veloso; 21.11.2010
comment
Правильное имя метода лишнее - person falko; 20.02.2014
comment
Как бы мне ни нравился этот ответ, похоже, что метод QuerySet.extra() находится на разделочной доске и в конечном итоге будет объявлен устаревшим. В документах django говорится: «Используйте этот метод в крайнем случае» и «Это старый API, который мы стремимся устареть в какой-то момент в будущем». - person jbiz; 02.12.2015

Для джанго >= 2.1

Вы можете отсортировать QuerySet, используя имена поиска месяца и дня в DateField.

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

Для джанго >= 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']
    )
    
person Munim Munna    schedule 04.07.2018

Более новые версии django имеют поиск по DateFields и DateTimeFields. https://docs.djangoproject.com/en/1.11/ref/models/database-functions/#extract

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

person Bobort    schedule 21.11.2017

Я тестировал с помощью 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')
person Fabiano Almeida    schedule 15.04.2018
comment
Пожалуйста, рассмотрите возможность добавления некоторых пояснений к вашему ответу. - person HMD; 15.04.2018

Post.objects.all().order_by('date_posted__minute').reverse(), где date_posted — ваш атрибут, который вы использовали в своей модели Post.

Пост - это всего лишь пример модели

person janaki sasidhar    schedule 30.07.2020
comment
Привет Джанаки, спасибо за публикацию! Добавление дополнительных деталей к вашему ответу и использование терминологии, которую они используют (месяц/день рождения, а не date_posted), поможет авторам понять ваш ответ без необходимости задавать дополнительные вопросы. Взгляните на другие ответы на этот вопрос, чтобы понять, что нужно. Это также помогает форматировать ваш код. - person Andrew Coates; 30.07.2020