2009-08-23 5 views
134

Ich versuche eine mit einem Datum zu vergleichen. Ich meine:Wie kann ich ein Datum eines DateTimeField in Django filtern?

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

Ich erhalte eine leere queryset Liste als Antwort, weil (ich glaube) ich keine Zeit am überlegen, aber ich will „jederzeit“.

Gibt es in Django einen einfachen Weg, dies zu tun?

Ich habe die Zeit in der Datetime eingestellt, es ist nicht 00:00.

+4

Dies ist ein von Belästigungen von Django. Wenn man bedenkt, dass dies ein einfacher und gebräuchlicher Anwendungsfall ist, gibt es keinen einfachen Weg, dies zu erreichen. – rubayeet

Antwort

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

// bearbeiten nach Kommentaren

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

doest nicht funktionieren, weil es auf 0 ein Datetime-Objekt mit Zeitwert gesetzt erzeugt, so dass die Zeit in der Datenbank nicht übereinstimmt.

+0

Dies ist der richtige Weg. Django Dokumentation ref? – hughdbrown

+0

Danke für die Antwort! Die erste Alternative funktioniert nicht mit Datetimefields. Die zweite Alternative funktioniert;). Wenn jemand eine andere Methode weiß, bitte antworten – Xidobix

+0

http://docs.python.org/library/datetime.html#datetime-objects Datumzeit mit() von Datetime-Modul Stunden, Minuten, Sekunden ist optional. die zweite ist von einem Arbeitsprojekt mit Vars ersetzt, können Sie in der Dokumentation suchen, es ist korrekt – zalew

0

siehe Artikel Django Documentation

Es ist sehr ähnlich wie die JZ Antwort

ur_data_model.objects.filter(ur_date_field=datetime(2005, 7, 27) 
+4

in der django Dokumentation funktioniert es, weil die datetimefiled Zeit 00.00 – Xidobix

0
Model.objects.filter(datetime__year=2011, datetime__month=2, datetime__day=30) 
100

Solche Lookups in django.views.generic.date_based implementiert sind wie folgt:

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

Weil es recht ausführlich ist Es gibt Pläne, die Syntax mitzu verbessernBediener. Überprüfen Sie "#9596 Comparing a DateTimeField to a date is too hard" für weitere Details.

+3

Verwendung mit einer Reichweite hat: 'Q (created__gte = datetime.combine (created_value, time.min))' – Dingo

+9

Sieht aus wie es in Django 1.9 landen wird: https : //github.com/django/django/commit/44f3ee77166bd5c0e8a4604f2d96015268dce100#diff-5e313dd49d68a0a867d830a7f442d2a6R2471 – amjoconn

+3

https://docs.djangoproject.com/de/1.9/ref/models/querysets/#date –

22

Dies erzeugt die gleichen Ergebnisse wie mit __year, __month und __day und scheint für mich zu arbeiten:

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

sieht so aus, als würde man date object in string umwandeln und einen Zeichenkettenvergleich von Daten durchführen, zwingt daher db, einen vollständigen Tabellenscan durchzuführen. für große Tische tötet dieser einen Ihre Leistung – yilmazhuseyin

1

Hm .. Meine Lösung funktioniert:

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

die oben ist, was ich benutzt habe. Es funktioniert nicht nur, es hat auch eine gewisse logische Unterstützung.

+2

Viel besser als alle anderen Antworten hier, danke! – Kin

+0

s-s-s-s-s-shazam! – dps

66

Hier sind die Ergebnisse, die ich mit ipython der timeit Funktion bekam:

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 

enthält schneller zu sein scheint.

+0

Diese Lösung scheint die neueste zu sein. Ich bin überrascht, dass es 4 upvotes gibt, denn wenn ich die 'contains'-Lösung ausprobiere, bekomme ich die Fehlermeldung:' Kann nicht für ' – Houman

+0

abrufen Ich überprüfe und aktualisiere Die Ergebnisse heute und ich glaube nicht, dass Ihr Fehler durch den Filter "__contains" verursacht wird. Wenn Sie jedoch auf Probleme stoßen, sollten Sie das Beispiel [django docs] (https://docs.djangoproject.com/en/dev/ref/models/querysets/#filter) ausprobieren, das '__gte' verwendet. – Moreno

+3

Die __contains-Methode funktioniert gut für mich. Ich denke, das ist wahrscheinlich die beste Antwort, da es Leistungsvergleiche bietet. Ich habe mehr als einen gewählt, aber ich bin überrascht, dass es nicht mehr Upvotes gibt. – RobotHumans

2

Hier ist eine interessante Technik-- Ich nutzte das startswith-Verfahren, wie es mit Django auf MySQL implementiert wurde, um das Ergebnis zu erzielen, nur nach einem Datum durch nur das Datum zu suchen. Im Grunde, wenn Django die Suche in der Datenbank durchführt, muss es eine String-Konvertierung für das DATETIME-MySQL-Speicherobjekt durchführen, so dass Sie darauf filtern können und den Zeitstempel des Datums weglassen - so entspricht% LIKE% nur dem Datum Objekt und Sie erhalten jeden Zeitstempel für das angegebene Datum.

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

Dies wird die folgende Abfrage ausführen:

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

Die LIKE BINARY in diesem Fall wird alles für das Datum übereinstimmen, egal, die Zeitstempel. Einschließlich Werte wie:

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

Hoffentlich hilft dies jedem bis Django mit einer Lösung herauskommt!

+0

Ok, also scheint dies die gleiche Antwort wie mhost und kettlebell oben zu sein, aber mit mehr Beschreibung dessen, was im Backend passiert. Zumindest haben Sie einen Grund, contains oder startswith zusammen mit dem date() -Attribut von datetime zu verwenden! – bbengfort

7

active_on Annahme ist ein Datumsobjekt, erhöht um 1 Tag tun dann Bereich

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

Jetzt Django __date queryset Filter hat Datetime-Objekte gegen Daten in Entwicklungsversion abzufragen. Somit wird es bald in 1.9 verfügbar sein.

+0

Yup, es wurde in 1.9 hinzugefügt https://docs.djangoproject.com/en/1.9/ref/models/querysets/#date – guival

+0

Beste Antwort, gültig für neuere Django-Versionen – serfer2

0

Es ist ein fantastisches Blogpost, die diese umfasst hier: Comparing Dates and Datetimes in the Django ORM

Die beste Lösung für Django geschrieben> 1,7, < 1.9 ist ein registrieren verwandeln:

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() 

Dann können Sie es in Ihren Filter verwenden wie folgt aus:

Foo.objects.filter(created_on__date=date) 

EDIT

Diese Lösung ist definitiv vom Backend abhängig. Aus dem Artikel:

Natürlich beruht diese Implementierung auf Ihrem besonderen Geschmack von SQL mit einer Funktion DATE(). MySQL tut das. So auch SQLite. Auf der anderen Seite habe ich nicht persönlich mit PostgreSQL gearbeitet, aber ein bisschen Googeln lässt mich glauben, dass es keine DATE() - Funktion hat. Eine so einfache Implementierung scheint also zwangsläufig etwas Backend-abhängig zu sein.

+0

ist das MySQL spezifisch? Ich wundere mich über die Wahl des Klassennamens. –

+0

@BinojDavid Ja, es ist Backend abhängig –

+0

Ich habe es mit Django 1.8 und PostgreSQL 9.6.6 getestet und es funktioniert perfekt. Mit PostgreSQL können Sie auch diese Syntax verwenden: 'return '{} :: date'.format (lhs), params' – maykel

16

Ab Django 1.9 verwenden Sie __date für ein Datetime-Objekt.

Zum Beispiel: MyObject.objects.filter(datetime_attr__date=datetime.date(2009,8,22))

1

In Django 1.7.6 Werke:

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

Dies funktioniert nur, wenn Sie nach dem genauen Datum suchen, für das Sie' __lte' nicht verwenden können Beispiel. – guival