Django'da sorgu nesnelerini tarih aralığına göre nasıl filtreleyebilirim?


248

Bir modelde şöyle bir alanım var:

class Sample(models.Model):
    date = fields.DateField(auto_now=False)

Şimdi, nesneleri bir tarih aralığına göre filtrelemem gerekiyor.

Nasıl arasında bir tarih olan tüm nesneleri filtrelerim 1-Jan-2011ve 31-Jan-2011?

Yanıtlar:


411

kullanım

Sample.objects.filter(date__range=["2011-01-01", "2011-01-31"])

Ya da sadece ayları akıllıca filtrelemeye çalışıyorsanız:

Sample.objects.filter(date__year='2011', 
                      date__month='01')

Düzenle

Bernhard Vallant'ın dediği gibi, dışlayan bir queryset istiyorsanız , gt / lt (daha büyük / daha küçük) kullanan çözümünüspecified range ends düşünmelisiniz .


Date1'in veri türü nedir? Artık datetime nesnem var.
user469652

8
@dcordjer: Ek olarak __range, sınırları içeren ( sql'ler gibi) söylenmelidir BETWEEN, sınırların dahil edilmesini istemiyorsanız gt / lt
çözümümle

Bu doğal olarak herhangi bir sıraya göre sıralanmış mı? Varsa, hangi sipariş? Teşekkürler.
Richard Dunn

1
@RichardDunn Sipariş, modelinizin varsayılan siparişine veya yukarıda belirtilenler tarafından order_byüretilene QuerySetgöre kullanılır filter. Yıllardır Django kullanmadım.
crodjer

date__range için gelecek ayın 01'ini koymanız gerekir. İşte tarihlerin 00: 00: 00.0000'e çevirdiği exmaplins belgeseline bir bağlantı, bu nedenle aralığınızdaki son gün dahil değildir. docs.djangoproject.com/tr/1.10/ref/models/querysets/#range bu durumda kullanıyorum: date__range = ["% s-% s-1"% (yıl, ay), "% s-% s- 1 "% (yıl, int (ay) +1)]
SpiRail

195

Sen kullanabilirsiniz Django'nınfilter ile datetime.datenesneler :

import datetime
samples = Sample.objects.filter(sampledate__gte=datetime.date(2011, 1, 1),
                                sampledate__lte=datetime.date(2011, 1, 31))

1. ve 31. günler dahil herşeyi elde etmek için gte'yi kullanmamız gerekecek değil mi?
Sam Stoelinga

1
Bu yöntemi kullanmanın bir yararı, dizeler yerine datetime nesnelerini iletebilmenizdir.
Brian Kung

79

Bir filtreyle django aralıkları yaparken, bir date nesnesiyle datetime nesnesinin kullanılması arasındaki farkı bildiğinizden emin olun. __range tarihler için kapsayıcıdır ancak bitiş tarihi için datetime nesnesi kullanırsanız, saat ayarlanmadıysa o günün girişlerini içermez.

    startdate = date.today()
    enddate = startdate + timedelta(days=6)
    Sample.objects.filter(date__range=[startdate, enddate])

bu tarihlerdeki girişler de dahil olmak üzere başlangıç ​​tarihinden bitiş tarihine kadar tüm girdileri döndürür. Kötü bir örnek, çünkü bu girişleri bir haftaya geleceğe döndürüyor, ancak sapmayı elde ediyorsunuz.

    startdate = datetime.today()
    enddate = startdate + timedelta(days=6)
    Sample.objects.filter(date__range=[startdate, enddate])

tarih alanlarının saatine göre ayarlanmış olan 24 saatlik girişler eksik olacaktır.


5
Bir datenesnenin nasıl içe aktarılacağını not etmek önemlidir : >>> from datetime import date >>> startdate = date.today()
Alex Spencer

19

Aralıktaki son tarihe bir gün eklemek için bir datetime.timedelta kullanarak , DateTimeField/datenesne karşılaştırmasındaki hassasiyet eksikliğinden kaynaklanan "empedans uyuşmazlığı" ile karşılaşabilirsiniz . Bu şu şekilde çalışır:

start = date(2012, 12, 11)
end = date(2012, 12, 18)
new_end = end + datetime.timedelta(days=1)

ExampleModel.objects.filter(some_datetime_field__range=[start, new_end])

Daha önce de tartışıldığı gibi, böyle bir şey yapmadan, kayıtlar son gün göz ardı edilir.

Düzenlenmeden kaçınmak için düzenlenmiş datetime.combine- a ile karşılaştırılırken DateTimeField, tek tek (ve kafa karıştırıcı) datetimenesnelerle uğraşmak yerine tarih örneklerine sadık kalmak daha mantıklı görünüyor . Aşağıdaki açıklamalarda daha fazla açıklamaya bakınız.


1
Bir kesme yöntemi ile bu basitleştiren müthiş Delorean kitaplığı yoktur: delorean.readthedocs.org/en/latest/quickstart.html#truncation
trojjer

@tojjer: umut verici görünüyor, buradaki kesme yöntemini nasıl kullanıyoruz?
eugene

@eugene: Bunu o aylar sonra tekrar araştırdım ve haklısın, sonuçta bu durumda gerçekten yardımcı olmuyor. Bunun etrafında düşünebildiğim tek yol, bir tarih örneğine filtre uygularken tarih-saat modeli alanı ile karşılaştırma için ekstra 'dolgu' sağlamak olan orijinal yanıtımda önerildiği gibi. Bu, yukarıdaki gibi datetime.combine yöntemiyle yapılabilir, ancak aralıktaki başlangıç ​​/ bitiş tarihine bir timedelta (gün = 1) ekleyerek yalnızca tutarsızlığı barındırmanın biraz daha basit olabileceğini fark ettim. - probleme bağlı olarak.
Mart'ta trojjer

Yani Example.objects.filter(created__range=[date(2014, 1, 1), date(2014, 2, 1)])üzerinde oluşturulan nesneler dahil olmaz date(2014, 2, 1)@cademan yardımsever açıklandığı gibi,. Ancak bitiş tarihini bir gün ekleyerek artırdıysanız, bu eksik nesneleri kapsayan bir sorgu kümesi elde edersiniz (ve date(2014, 2, 2)aynı tuhaflık nedeniyle oluşturulan nesneleri rahatça atlayabilirsiniz ). Buradaki can sıkıcı şey, ile belirtilen bir 'manuel' aralığın created__gte ... created__lte=date(2014, 2, 1)da işe yaramamasıdır, ki bu kesinlikle sezgisel IMHO'dur.
Mart'ta trojjer

1
@tojjer: datetime_field__range = [delorean.parse ('2014-01-01'). tarih, delorean.parse ('2014-02-01'). tarih] benim için çalışıyor
eugene

1

Basit,

YourModel.objects.filter(YOUR_DATE_FIELD__date=timezone.now())

Benim için çalışıyor


3
Bu benim için de işe yaradı, netlik için noobs için: (date__date = ...) anlamına gelir ({whateverColumnTheDateIsCalled} __ tarih)
Ryan Dines

2
OP bir aralık istedi ancak
aliasav

1

Daha esnek hale getirmek için, aşağıdaki gibi bir FilterBackend tasarlayabilirsiniz:

class AnalyticsFilterBackend(generic_filters.BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        predicate = request.query_params # or request.data for POST

        if predicate.get('from_date', None) is not None and predicate.get('to_date', None) is not None:
            queryset = queryset.filter(your_date__range=(predicate['from_date'], predicate['to_date']))

        if predicate.get('from_date', None) is not None and predicate.get('to_date', None) is None:
            queryset = queryset.filter(your_date__gte=predicate['from_date'])

        if predicate.get('to_date', None) is not None and predicate.get('from_date', None) is None:
            queryset = queryset.filter(your_date__lte=predicate['to_date'])
        return queryset

-2

Bugün hala geçerli. Ayrıca şunları da yapabilirsiniz:

import dateutil
import pytz

date = dateutil.parser.parse('02/11/2019').replace(tzinfo=pytz.UTC)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.