Django'da bir DateTimeField tarihini nasıl filtreleyebilirim?


173

DateTimeFieldBir tarihle karşılaştırmayı filtrelemeye çalışıyorum . Demek istediğim:

MyObject.objects.filter(datetime_attr=datetime.date(2009,8,22))

Cevap olarak boş bir queryset listesi alıyorum çünkü (sanırım) zamanı düşünmüyorum, ama “her zaman” istiyorum.

Django'da bunu yapmanın kolay bir yolu var mı?

Ayarlanan tarihte vaktim var, öyle değil 00:00.


5
Bu Django'nun sıkıntılarından biri. Bunun basit ve yaygın bir kullanım durumu olduğu düşünüldüğünde, bunu başarmanın basit bir yolu yoktur.
rubayeet

Yanıtlar:


114

Bu tür aramalar django.views.generic.date_basedaşağıdaki gibi uygulanır :

{'date_time_field__range': (datetime.datetime.combine(date, datetime.time.min),
                            datetime.datetime.combine(date, datetime.time.max))} 

Oldukça ayrıntılı olduğundan, __dateoperatörü kullanarak sözdizimini iyileştirme planları vardır . Daha fazla ayrıntı için " # 9596 Bir DateTimeField öğesini bir tarihle karşılaştırmak çok zor " seçeneğini işaretleyin.


4
Aralık ile kullanma: Q(created__gte=datetime.combine(created_value, time.min))
Dingo

10
Görünüşe göre Django 1.9'a inecek
amjoconn

14
Django 1.9 Yeni:Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
Sigara

102
YourModel.objects.filter(datetime_published__year='2008', 
                         datetime_published__month='03', 
                         datetime_published__day='27')

// yorumlardan sonra düzenle

YourModel.objects.filter(datetime_published=datetime(2008, 03, 27))

doest çalışmaz, çünkü zaman değerleri 0 olarak ayarlanmış bir datetime nesnesi oluşturur, böylece veritabanındaki zaman eşleşmez.


cevap için teşekkürler! ilk alternatif datetimefields ile çalışmaz. İkinci alternatif işler;). Birisi başka bir yöntem biliyorsa lütfen cevap verin
Xidobix

dot.tothon.org/library/datetime.html#datetime-objects datetime modülünden datetime () kullanarak saat, dakika, saniye isteğe bağlıdır. ikincisi vars değiştirilmiş çalışan bir projeden, doğru olan belgelere bakabilirsiniz
zalew

isteğe bağlı olduğunu biliyorum, sorun benim datetimefield zaman
ayarlanmış

"ilk alternatif datetimefields ile çalışmaz." datetime.datetime () bir datetime nesnesi döndürdüğü için oldukça şaşırtıcı olurdu djangoproject.com/documentation/0.96/models/basic model tanımını ve örneklerini kontrol edin: pub_date = models.DateTimeField () pub_date = datetime (2005, 7, 30)
zalew

"Isteğe bağlı olduğunu biliyorum, sorun benim datetimefield zaman ayarlanmış olması, 00:00 değil" Oh, şimdi anladım. Evet, hiçbir zaman argümanı ile 00'a
ayarlanmıştır

88

İşte ipython'un timeit işleviyle elde ettiğim sonuçlar:

from datetime import date
today = date.today()

timeit[Model.objects.filter(date_created__year=today.year, date_created__month=today.month, date_created__day=today.day)]
1000 loops, best of 3: 652 us per loop

timeit[Model.objects.filter(date_created__gte=today)]
1000 loops, best of 3: 631 us per loop

timeit[Model.objects.filter(date_created__startswith=today)]
1000 loops, best of 3: 541 us per loop

timeit[Model.objects.filter(date_created__contains=today)]
1000 loops, best of 3: 536 us per loop

içeren daha hızlı görünüyor.


Bu çözüm en yeni gibi görünüyor. Ben 4 upvotes var şaşırdım, çünkü containsçözümü denemek , hata mesajı alıyorum:Unable to get repr for <class 'django.db.models.query.QuerySet'>
Houman

Sonuçları bugün tekrar kontrol ediyorum ve güncelliyorum ve hatanın __containsfiltreden kaynaklandığını düşünmüyorum . Ancak sorun yaşıyorsanız , kullanılan django dokümanı örneğini denemelisiniz __gte.
Moreno

4
__Contains yöntemi benim için iyi çalışıyor. Performans karşılaştırmaları sağladığı için bu muhtemelen en iyi cevaptır. Birden fazla oy verdim, ancak daha fazla oy vermediğine şaşırdım.
RobotHumans

startswithÇözümü seviyorum ..
w411 3

46

Şimdi Django, datetime nesnelerini geliştirme sürümünde tarihlere göre sorgulamak için __date queryset filtresine sahiptir . Böylece, yakında 1.9'da satışa sunulacak.


Evet, 1.9 dokümana
guival

En iyi yanıt, daha yeni Django sürümleri için geçerlidir
serfer2

Django 1.11 olduğum :( Bu benim için işi yapmaz, hiçbir fikri neden benim tam istisna değildir: NotImplementedError: basedatabaseoperations alt sınıfları bir datetime_cast_date () yöntemini gerektirebilir
AbdurRehman Han

44
Mymodel.objects.filter(date_time_field__contains=datetime.date(1986, 7, 28))

yukarıda kullandığım şey. Sadece işe yaramaz, aynı zamanda bazı doğal mantıksal desteğe sahiptir.


3
Buradaki diğer cevapların hepsinden çok daha iyi, teşekkürler!
Kin

sssss-shazam! 💯
dps

30

Django 1.9'dan itibaren bunu yapmanın yolu __datedatetime nesnesini kullanmaktır.

Örneğin: MyObject.objects.filter(datetime_attr__date=datetime.date(2009,8,22))


27

Bu, __year, __month ve __day kullanmakla aynı sonuçları üretir ve benim için çalışıyor gibi görünüyor:

YourModel.objects.filter(your_datetime_field__startswith=datetime.date(2009,8,22))

19
Bu, tarih nesnesini dizeye çevirir ve tarihlerin dize karşılaştırmasını yapar, bu nedenle db'yi tam tablo taraması yapmaya zorlar. büyük tablolar için bu performansınızı öldürmek
yilmazhuseyin

8

active_on öğesinin bir tarih nesnesi olduğunu varsayarak, bunu 1 gün artırın ve sonra aralık yapın

next_day = active_on + datetime.timedelta(1)
queryset = queryset.filter(date_created__range=(active_on, next_day) )

2

İşte ilginç bir teknik - sadece tarih boyunca bir tarih araması sonucunu elde etmek için MySQL'de Django ile uygulanan prosedürü kullanarak başlattım. Temel olarak, Django veritabanında arama yaptığında DATETIME MySQL depolama nesnesi için bir dize dönüştürme işlemi yapmak zorundadır, böylece tarihin zaman damgası kısmını dışarıda bırakarak filtreleyebilirsiniz - bu şekilde% LIKE% yalnızca tarihle eşleşir nesnesi ve belirtilen tarih için her zaman damgasını alırsınız.

datetime_filter = datetime(2009, 8, 22) 
MyObject.objects.filter(datetime_attr__startswith=datetime_filter.date())

Bu, aşağıdaki sorguyu gerçekleştirir:

SELECT (values) FROM myapp_my_object \ 
WHERE myapp_my_object.datetime_attr LIKE BINARY 2009-08-22%

Bu durumda GİBİ İKİLİ gibi, zaman damgası ne olursa olsun, tarih için her şeyle eşleşecektir. Gibi değerler dahil:

+---------------------+
| datetime_attr       |
+---------------------+
| 2009-08-22 11:05:08 |
+---------------------+

Umarım bu Django bir çözüm çıkana kadar herkese yardımcı olur!


Tamam, bu yukarıdaki hayalet ve kettlehell ile aynı cevap gibi görünüyor, ancak arka uçta neler olduğuna dair daha fazla açıklama ile. En azından datetime öğesinin date () özniteliği ile birlikte include veya startsw kullanmak için bir nedeniniz var!
bbengfort

2

Burada bunu kapsayan harika bir blog yazısı var: Django ORM'deki Tarihleri ​​ve Günleri Karşılaştırmak

Django> 1.7, <1.9 için yayınlanan en iyi çözüm bir dönüşüm kaydetmektir:

from django.db import models

class MySQLDatetimeDate(models.Transform):
    """
    This implements a custom SQL lookup when using `__date` with datetimes.
    To enable filtering on datetimes that fall on a given date, import
    this transform and register it with the DateTimeField.
    """
    lookup_name = 'date'

    def as_sql(self, compiler, connection):
        lhs, params = compiler.compile(self.lhs)
        return 'DATE({})'.format(lhs), params

    @property
    def output_field(self):
        return models.DateField()

Ardından filtrelerinizde şu şekilde kullanabilirsiniz:

Foo.objects.filter(created_on__date=date)

DÜZENLE

Bu çözüm kesinlikle arka uca bağımlıdır. Makaleden:

Tabii ki, bu uygulama bir DATE () işlevine sahip özel SQL lezzetinize dayanmaktadır. MySQL bunu yapar. SQLite de öyle. Öte yandan, PostgreSQL ile kişisel olarak çalışmadım, ancak bazı googling bir DATE () işlevi olmadığına inanmamı sağlıyor. Yani bu basit bir uygulama mutlaka arka uca bağımlı olacak gibi görünüyor.


bu MySQL'e özgü mü? sınıf ismi seçimi merak ediyorum.
Binoj David

@BinojDavid Evet, arka uca bağımlı
Dan Gayle

Django 1.8 ve PostgreSQL 9.6.6 kullanarak test ettim ve mükemmel çalışıyor. Aslında PostgreSQL kullanarak bu sözdizimini de kullanabilirsiniz:return '{}::date'.format(lhs), params
michal-michalak

1

Hm .. Çözümüm çalışıyor:

Mymodel.objects.filter(date_time_field__startswith=datetime.datetime(1986, 7, 28))


0

Django 1.7.6 çalışmalarında:

MyObject.objects.filter(datetime_attr__startswith=datetime.date(2009,8,22))

2
Bu yalnızca kesin tarihi arıyorsanız çalışır, __lteörneğin kullanamazsınız .
guival

-1

Django Belgeleri makalesine bakın

ur_data_model.objects.filter(ur_date_field__gte=datetime(2009, 8, 22), ur_date_field__lt=datetime(2009, 8, 23))

5
django belgelerinde datetimefiled zamanı olduğu için çalışır 00:00
Xidobix
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.