2012-05-09 13 views
10

Mam model, który zawiera datefield. Próbuję uzyskać zestaw kwerend tego modelu, który zawiera bieżący tydzień (rozpoczyna się w poniedziałek).Filtrowanie zapytań Django według numeru tygodnia ISO

Ponieważ Django datefield zawiera prosty model datetime.date, który zgodnie z założeniem powinien zostać przefiltrowany przy użyciu .isocalendar(). Logicznie jest to dokładnie to, czego chcę, bez dodatkowych porównań i obliczeń według bieżącego dnia tygodnia.

Więc to, co chcę robić w istocie jest siła .filter oświadczenie zachowywać się w tej logice:

if model.date.isocalendar()[2] == datetime.date.today().isocalendar()[2] 
    ... 

Jednak jak napisać go wewnątrz oświadczenie filtra? .filter(model__date__isocalendar=datetime.date.today().isocalendar()) spowoduje błędne wyniki (takie same jak w porównaniu do dzisiaj, nie w tym tygodniu).

jak wykopy prawdziwej http://docs.python.org/library/datetime.html nie zauważyłem żadnych innych opcji dzień tygodnia ...

Uwaga od dokumentacji:

date.isocalendar() Zwraca 3-krotki (rok ISO , Numer tygodnia ISO, ISO w dni powszednie).

Aktualizacja:

Choć lubił rozwiązanie przy użyciu zakresów jeszcze jest najlepszym rozwiązaniem. Jednak w moim przypadku stworzyłem zmienną, która oznacza początek tygodnia i po prostu wyglądam na większą lub jednakową wartość, ponieważ jeśli szukam meczów na bieżący tydzień. W przypadku podania numeru tygodnia Wymagałoby to obu końców.

today = datetime.date.today() 
monday = today - datetime.timedelta(days=today.weekday()) 

... \ 
.filter(date__gte=monday) 
+0

ja nie wiem, czy wsparcie ORM, które jednak można awaryjny do surowego zapytania, jeśli nie https://docs.djangoproject.com/en/dev/topics/db/sql/ – dm03514

+0

Jestem świadomy tej opcji dm03514, ale wolałbym napisać wtedy własny filtr. Jest to również opcja, ale chciałbym wiedzieć, że możliwe jest osiągnięcie tego przy pomocy domyślnych akcji w Django bez rozszerzania go. – JackLeo

+1

przy okazji jest fajny moduł python dateutil, który może być pomocny http://pypi.python.org/pypi/python-dateutil – aisbaa

Odpowiedz

8

Nie będziesz w stanie tego zrobić. Pamiętaj, że nie jest to tylko kwestia tego, co obsługuje Python, Django musi przekazywać filtr do bazy danych, a baza danych nie obsługuje tak złożonych obliczeń daty. Możesz może użyć __range, jednak z datą rozpoczęcia i datą zakończenia.

+0

Tak, również użyłbym * __ zasięgu *, może dodać niestandardowy ModelManager i niestandardowy Queryset z * tygodniem (date_field = (2012, 18)) * metoda. – aisbaa

+0

Wiem o opcji zasięgu, ale unikałem jej ze względu na liczbę akcji, która jest wymagana do uzyskania obu końcówek tygodnia, ale myślę, że to może być mniejsze zło. Dzięki, nie mniej. – JackLeo

+1

Tak, nie każda część aplikacji musi być zakodowana w kodzie golfowym. Czasami trzeba wziąć dłuższą ścieżkę. Zawsze rób to, co najprościej, najbardziej oczywiste, i twórz najmniejszy ślad (modyfikując sposób, w jaki Django obsługuje filtry, zostawiłoby całkiem duży ślad). –

1

(Ta odpowiedź powinna pracować tylko dla PostgreSQL, ale może pracować dla innych baz danych.)

Szybkie i eleganckie rozwiązanie dla tego problemu byłoby zdefiniować te dwa custom transformers:

from django.db import models 
from django.db.models.lookups import DateTransform 

@models.DateTimeField.register_lookup 
class WeekTransform(DateTransform): 
    lookup_name = 'week' 


@models.DateTimeField.register_lookup 
class ISOYearTransform(DateTransform): 
    lookup_name = 'isoyear' 

teraz ty może zapytać przez tydzień tak:

from django.utils.timezone import now 
year, week, _ = now().isocalendar() 

MyModel.objects.filter(created__isoyear=year, created__week=week) 

tyłki kulisy, obiekt Django DateTransform wykorzystuje postgres EXTRACT function, które s upsports week i isoyear.

0

ExtractWeek został wprowadzony w Django 1.11 do filtrowania na podstawie numeru isoweek.

Dla Django 1.10 i niższe wersje, następujące rozwiązanie działa na filtrowanie według numeru ISO tygodnia na bazie postgres:

from django.db.models.functions import Extract 
from django.db import models 
@models.DateTimeField.register_lookup 
class ExtractWeek(Extract): 
    lookup_name = 'week' 

teraz zrobić kwerendę następująco

queryset.annotate(week=ExtractWeek('date'))\ 
      .filter(week=week_number)