ฉันจะกรองวันที่ของ DateTimeField ใน Django ได้อย่างไร


173

ฉันพยายามกรองการDateTimeFieldเปรียบเทียบกับวันที่ ฉันหมายถึง:

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

ฉันได้รับรายการชุดแบบสอบถามที่ว่างเปล่าเป็นคำตอบเพราะ (ฉันคิดว่า) ฉันไม่ได้พิจารณาเวลา แต่ฉันต้องการ "ตลอดเวลา"

Django มีวิธีที่ง่ายในการทำเช่นนี้หรือไม่?

ฉันมีเวลาที่กำหนดไว้ใน datetime มันไม่ใช่ 00:00ก็ไม่ได้เป็น


5
นี่คือหนึ่งในความรำคาญของ Django พิจารณาว่านี่เป็นกรณีการใช้งานที่ง่ายและทั่วไปไม่มีวิธีง่ายๆในการบรรลุเป้าหมายนี้
rubayeet

ที่เกี่ยวข้อง: stackoverflow.com/a/22085678/2859614
MackM

คำตอบ:


114

การค้นหาดังกล่าวมีการใช้งานในdjango.views.generic.date_basedดังนี้:

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

เนื่องจากค่อนข้างชัดเจนว่ามีแผนการที่จะปรับปรุงไวยากรณ์โดยใช้__dateโอเปอเรเตอร์ ทำเครื่องหมาย " # 9596 การเปรียบเทียบ DateTimeField กับวันที่นั้นยากเกินไป " สำหรับรายละเอียดเพิ่มเติม


4
ใช้กับช่วง: Q(created__gte=datetime.combine(created_value, time.min))
Dingo

10
ดูเหมือนว่าจะลงจอดใน Django 1.9: github.com/django/django/commit/…
amjoconn

14
ใหม่ใน Django 1.9:Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
ไม่ใช่

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

// แก้ไขหลังจากความคิดเห็น

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

doest ไม่ทำงานเพราะมันสร้างวัตถุวันที่และเวลาที่ตั้งค่าเป็น 0 ดังนั้นเวลาในฐานข้อมูลไม่ตรงกัน


ขอบคุณสำหรับคำตอบ! ทางเลือกแรกไม่สามารถใช้งานได้กับ datetimefields ทางเลือกที่สองใช้งานได้;) ถ้ามีคนรู้วิธีอื่นโปรดคำตอบ
Xidobix

docs.python.org/library/datetime.html#datetime-objects โดยใช้ datetime () จากโมดูล datetime ชั่วโมง, นาที, วินาที, วินาทีเป็นตัวเลือก สองคือจากโครงการทำงานร่วมกับ VARs แทนที่คุณสามารถดูในเอกสารว่าถูกต้อง
zalew

ฉันรู้ว่ามันเป็นตัวเลือกปัญหาคือ datetimefield ของฉันมีเวลาที่กำหนดไว้ไม่ใช่ 00:00
Xidobix

"ทางเลือกแรกไม่สามารถใช้งานกับเขตข้อมูลได้" มันค่อนข้างน่าแปลกใจเพราะ datetime.datetime () ส่งคืนวัตถุ datetime djangoproject.com/documentation/0.96/models/basicตรวจสอบนิยามของโมเดลและตัวอย่าง: pub_date = models.DateTimeField () pub_date = datetime (2005, 7, 30)
zalew

"ฉันรู้ว่ามันเป็นตัวเลือกปัญหาคือ datetimefield ของฉันมีเวลาที่กำหนดไว้ไม่ใช่ 00:00" โอ้ตอนนี้ฉันได้รับแล้ว ใช่ไม่มีข้อโต้แย้งเวลามันตั้ง 00 ดังนั้นจึงไม่กลับมา :)
zalew

88

นี่คือผลลัพธ์ที่ฉันได้รับจากฟังก์ชัน timeit ของ ipython:

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

มีน่าจะเป็นได้เร็วขึ้น


ดูเหมือนว่าวิธีนี้จะเป็นวิธีแก้ปัญหาล่าสุด ฉันประหลาดใจที่มันมี 4 upvotes เพราะเมื่อฉันลองcontainsวิธีการแก้ปัญหาฉันได้รับข้อความแสดงข้อผิดพลาด:Unable to get repr for <class 'django.db.models.query.QuerySet'>
Houman

ฉันตรวจสอบและอัปเดตผลลัพธ์ในวันนี้และฉันไม่คิดว่าข้อผิดพลาดของคุณเกิดจาก__containsตัวกรอง แต่หากคุณพบปัญหาคุณควรลองตัวอย่าง django docsที่ใช้งาน__gteอยู่
Moreno

4
วิธี __contain นั้นใช้ได้ผลดีสำหรับฉัน ฉันคิดว่านี่อาจเป็นคำตอบที่ดีที่สุดเนื่องจากมีการเปรียบเทียบประสิทธิภาพ ฉันลงคะแนนมากกว่าหนึ่ง แต่ฉันประหลาดใจที่ไม่มี upvotes มากขึ้น
RobotHumans

ฉันรักstartswithทางออก ..
w411 3

46

ตอนนี้ Django มี__ วันที่ตัวกรองชุดการสืบค้นวัตถุวันที่และเวลากับวันที่ในรุ่นพัฒนา ดังนั้นจะมีให้ใน 1.9 เร็ว ๆ นี้


ใช่มันถูกเพิ่มเข้าไปใน 1.9 docs.djangoproject.com/en/1.9/ref/models/querysets/#date
guival

คำตอบที่ดีที่สุดใช้ได้สำหรับ Django เวอร์ชั่นใหม่
serfer2 2

นี้ไม่ทำงานสำหรับฉันคิดว่าทำไม :( ฉันใน Django 1.11 ยกเว้นที่แน่นอนของฉันคือ: NotImplementedError: subclasses ของ basedatabaseoperations อาจต้องใช้ datetime_cast_date () วิธีการ
AbdurRehman ข่าน

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

ด้านบนคือสิ่งที่ฉันใช้ ไม่เพียงทำงานได้ แต่ยังมีการสำรองข้อมูลเชิงตรรกะอยู่ด้วย


3
ดีกว่าคำตอบอื่น ๆ ทั้งหมดที่นี่ขอบคุณ!
Kin

sssss-แซม! 💯
dps


27

สิ่งนี้ให้ผลลัพธ์เช่นเดียวกับการใช้ __year, __month และ __day และดูเหมือนจะใช้ได้สำหรับฉัน:

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

19
ดูเหมือนว่าวัตถุนี้เปลี่ยนวันที่เป็นสตริงและทำการเปรียบเทียบสตริงของวันที่ดังนั้นบังคับให้ db ทำการสแกนตารางแบบเต็ม สำหรับตารางขนาดใหญ่อันนี้ฆ่าการแสดงของคุณ
yilmazhuseyin

8

สมมติว่า active_on เป็นวัตถุวันที่เพิ่มขึ้น 1 วันจากนั้นทำช่วง

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

2

นี่เป็นเทคนิคที่น่าสนใจ - ฉันใช้ประโยชน์จากขั้นตอนการเริ่มต้นที่ได้ดำเนินการกับ Django บน MySQL เพื่อให้ได้ผลลัพธ์ของการค้นหาเฉพาะวันที่และเวลาผ่านวันที่เท่านั้น โดยทั่วไปเมื่อ Django ทำการค้นหาในฐานข้อมูลมันจะต้องทำการแปลงสตริงสำหรับวัตถุเก็บข้อมูล MySQL DATETIME เพื่อให้คุณสามารถกรองสิ่งนั้นโดยปล่อยส่วนเวลาประทับของวันที่ -% LIKE% จะตรงกับวันที่เท่านั้น วัตถุและคุณจะได้รับการประทับเวลาทุกครั้งสำหรับวันที่กำหนด

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

สิ่งนี้จะทำการค้นหาต่อไปนี้:

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

LIKE BINARY ในกรณีนี้จะตรงกับทุกอย่างสำหรับวันที่ไม่ว่าเวลาจะเป็นเท่าไหร่ รวมถึงค่าเช่น:

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

หวังว่านี่จะช่วยทุกคนจนกว่า Django จะออกมาพร้อมทางออก!


ตกลงดังนั้นนี่ดูเหมือนจะเป็นคำตอบเดียวกับ mhost และ kettlehell ด้านบน แต่มีคำอธิบายเพิ่มเติมเกี่ยวกับสิ่งที่เกิดขึ้นในแบ็กเอนด์ อย่างน้อยคุณก็มีเหตุผลที่จะใช้มีหรือเริ่มต้นพร้อมกับวันที่ () แอตทริบิวต์ของ datetime!
bbengfort

2

มีบล็อกโพสต์ที่น่าอัศจรรย์ซึ่งครอบคลุมที่นี่: การเปรียบเทียบวันที่และชุดข้อมูลใน Django ORM

ทางออกที่ดีที่สุดสำหรับ Django> 1.7, <1.9 คือการลงทะเบียนการแปลง:

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

จากนั้นคุณสามารถใช้มันในตัวกรองของคุณเช่นนี้:

Foo.objects.filter(created_on__date=date)

แก้ไข

วิธีการแก้ปัญหานี้ขึ้นอยู่กับการสิ้นสุดกลับแน่นอน จากบทความ:

แน่นอนว่าการติดตั้งนี้ขึ้นอยู่กับรสชาติของ SQL ที่มีฟังก์ชั่น DATE () MySQL ทำ ดังนั้น SQLite ในทางกลับกันฉันไม่ได้ทำงานกับ PostgreSQL เป็นการส่วนตัว แต่ googling ทำให้ฉันเชื่อว่ามันไม่มีฟังก์ชั่น DATE () ดังนั้นการดำเนินการนี้ง่ายดูเหมือนว่ามันจะจำเป็นต้องขึ้นอยู่กับแบ็กเอนด์ค่อนข้าง


เป็น MySQL เฉพาะหรือไม่ สงสัยเกี่ยวกับตัวเลือกชื่อคลาส
Binoj David

@BinojDavid ใช่มันขึ้นอยู่กับแบ็กเอนด์
แดนแกรี

ฉันทดสอบโดยใช้ Django 1.8 และ PostgreSQL 9.6.6 และทำงานได้อย่างสมบูรณ์ การใช้ PostgreSQL จริงๆแล้วคุณสามารถใช้return '{}::date'.format(lhs), params
ซินแทก

1

อืม .. โซลูชั่นของฉันใช้งานได้:

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


0

ใน Django 1.7.6 ทำงาน:

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

2
ใช้งานได้เฉพาะถ้าคุณกำลังมองหาวันที่แน่นอนคุณไม่สามารถใช้__lteตัวอย่าง
guival

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.