ฉันจะกรองวัตถุคิวรี่ตามช่วงวันที่ใน Django ได้อย่างไร


248

ฉันมีฟิลด์ในหนึ่งโมเดลเช่น:

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

ตอนนี้ฉันต้องกรองวัตถุตามช่วงวันที่

ฉันจะกรองวัตถุทั้งหมดที่มีวันที่ระหว่าง1-Jan-2011และ31-Jan-2011อย่างไร

คำตอบ:


411

ใช้

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

หรือถ้าคุณแค่พยายามกรองเดือนที่ชาญฉลาด:

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

แก้ไข

ดังที่ Bernhard Vallant กล่าวหากคุณต้องการชุดข้อมูลที่ไม่รวมspecified range endsคุณควรพิจารณาโซลูชันของเขาซึ่งใช้ gt / lt (มากกว่า / น้อยกว่า)


ประเภทข้อมูลของ date1 คืออะไร ฉันมีวัตถุ datetime แล้ว
user469652

8
@dcordjer: Additinally ควรจะกล่าวว่า__rangeมีเส้นขอบ (เช่น SQL ของBETWEEN) ถ้าคุณไม่ต้องการพรมแดนรวมที่คุณจะต้องไปกับฉัน gt โซลูชัน / ลิตร ...
เบอร์นาร์ด Vallant

นี่คือการเรียงลำดับโดยเนื้อแท้หรือไม่? ถ้าเป็นเช่นนั้นคำสั่งใด? ขอบคุณ
Richard Dunn

1
@RichardDunn การสั่งซื้อจะขึ้นอยู่กับการสั่งซื้อเริ่มต้นของรุ่นของคุณหรือหากคุณใช้order_byมากกว่าสิ่งที่สร้างขึ้นQuerySetfilterโดยการดังกล่าวข้างต้น ฉันไม่ได้ใช้ Django มาหลายปีแล้ว
crodjer

สำหรับ date__range คุณต้องใส่ 01 ของเดือนถัดไป นี่คือลิงค์ไปยังเอกสารที่ exmaplins แปลเป็น 00: 00: 00.0000 ของวันที่ดังนั้นวันสุดท้ายในช่วงของคุณจะไม่รวมอยู่ docs.djangoproject.com/en/1.10/ref/models/querysets/#range ในกรณีนี้ฉันใช้: date__range = ["% s-% s-1"% (ปี, เดือน), "% s-% s- 1 "% (ปี, int (เดือน) +1)]
SpiRail

195

คุณสามารถใช้djangofilterกับdatetime.dateวัตถุ :

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

เพื่อให้ได้ทุกอย่างรวมถึงวันที่ 1 และ 31 เราจะต้องใช้ gte ใช่มั้ย
Sam Stoelinga

1
ข้อดีของการใช้เมธอดนี้กับ crodjer's คือคุณสามารถส่งมันไปยังวัตถุเวลาและวันที่แทนสตริง
Brian Kung

79

เมื่อทำช่วง django ด้วยตัวกรองตรวจสอบให้แน่ใจว่าคุณทราบความแตกต่างระหว่างการใช้วัตถุวันที่เทียบกับวัตถุวันที่และเวลา __range รวมอยู่ในวันที่ แต่ถ้าคุณใช้วัตถุ datetime สำหรับวันที่สิ้นสุดมันจะไม่รวมรายการสำหรับวันนั้นหากไม่ได้ตั้งเวลาไว้

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

ส่งคืนรายการทั้งหมดจาก startdate ถึง enddate รวมถึงรายการในวันที่เหล่านั้น ตัวอย่างที่ไม่ดีเนื่องจากนี่คือการส่งคืนรายการต่อสัปดาห์ในอนาคต แต่คุณจะได้รับการเลื่อน

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

จะหายไป 24 ชั่วโมงมูลค่ารายการขึ้นอยู่กับเวลาสำหรับฟิลด์วันที่ที่ถูกตั้งค่าเป็น


5
ฉันคิดว่ามันเป็นสิ่งสำคัญที่จะต้องทราบวิธีการที่จะนำเข้าdateวัตถุ: >>> from datetime import date >>> startdate = date.today()
อเล็กซ์สเปนเซอร์

19

คุณจะได้รับรอบ "ต้านทานไม่ตรงกัน" เกิดจากการขาดความแม่นยำในการDateTimeField/dateเปรียบเทียบวัตถุ - ที่สามารถเกิดขึ้นได้หากใช้ช่วง - โดยใช้datetime.timedeltaเพื่อเพิ่มวันถึงวันสุดท้ายในช่วง งานนี้ชอบ:

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

ตามที่กล่าวไว้ก่อนหน้านี้โดยไม่ทำสิ่งนี้บันทึกจะถูกละเว้นในวันสุดท้าย

แก้ไขเพื่อหลีกเลี่ยงการใช้datetime.combine- ดูเหมือนมีเหตุผลมากกว่าที่จะยึดติดกับอินสแตนซ์วันที่เมื่อเปรียบเทียบกับ a DateTimeFieldแทนที่จะยุ่งเกี่ยวกับdatetimeวัตถุที่ถูกโยนทิ้ง (และทำให้สับสน) ดูคำอธิบายเพิ่มเติมในความคิดเห็นด้านล่าง


1
มีห้องสมุด Delorean น่ากลัวที่ช่วยลดความยุ่งยากนี้ด้วยวิธีการตัดเป็น: delorean.readthedocs.org/en/latest/quickstart.html#truncation
trojjer

@tojer: ดูมีแนวโน้มเราจะใช้วิธีการตัดทอนที่นี่ได้อย่างไร
eugene

@eugene: ฉันสำรวจมันอีกครั้งในตอนนี้หลังจากผ่านไปหลายเดือนและคุณพูดถูกมันไม่ได้ช่วยอะไรเลยในสถานการณ์แบบนี้ วิธีเดียวที่อยู่รอบ ๆ มันที่ฉันคิดได้ก็คือแนะนำในการตอบกลับดั้งเดิมของฉันซึ่งก็คือการจัดหา 'ช่องว่างภายใน' เพิ่มเติมเพื่อเปรียบเทียบกับเขตข้อมูลรูปแบบวันที่และเวลาเมื่อคุณกรองกับอินสแตนซ์วันที่ ซึ่งสามารถทำได้ผ่านวิธี datetime.combine ดังกล่าวข้างต้น แต่ฉันได้พบว่ามันง่ายกว่าเล็กน้อยที่จะรองรับความคลาดเคลื่อนเพียงเล็กน้อยโดยการเพิ่ม timedelta (days = 1) ในวันที่เริ่มต้น / สิ้นสุดในช่วง - - ขึ้นอยู่กับปัญหา
trojjer

ดังนั้นExample.objects.filter(created__range=[date(2014, 1, 1), date(2014, 2, 1)])จะไม่รวมวัตถุที่สร้างขึ้นdate(2014, 2, 1)เช่น @cademan อธิบายอย่างเป็นประโยชน์ แต่ถ้าคุณเพิ่มขึ้นวันที่สิ้นสุดโดยการเพิ่มวันหนึ่งคุณจะได้รับชุดข้อความค้นหาที่ครอบคลุมวัตถุที่หายไปเหล่านั้น (และสะดวกถนัดวัตถุที่สร้างขึ้นบนdate(2014, 2, 2)เพราะมุมแหลมเดียวกัน) สิ่งที่น่ารำคาญที่นี่คือช่วง 'คู่มือ' ที่ระบุด้วยcreated__gte ... created__lte=date(2014, 2, 1)ไม่ทำงานซึ่งเป็น IMHO ที่ตอบโต้ได้ง่ายอย่างแน่นอน
trojjer

1
@tojjer: datetime_field__range = [delorean.parse ('2014-01-01'). วันที่, delorean.parse ('2014-02-01'). วันที่] ทำงานให้ฉัน
eugene

1

ง่ายมาก

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

ใช้งานได้สำหรับฉัน


3
นี้ทำงานสำหรับฉันเช่นกันสำหรับ noobs เพื่อความชัดเจน: (date__date = ... ) หมายถึง ({whatColumnTheDateIsCalled} __ date)
Ryan Dines

2
OP ขอช่วง แต่
aliasav

1

เพื่อให้มีความยืดหยุ่นมากขึ้นคุณสามารถออกแบบ FilterBackend ดังนี้:

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

ยังคงมีความเกี่ยวข้องในวันนี้ คุณยังสามารถทำสิ่งต่อไปนี้

import dateutil
import pytz

date = dateutil.parser.parse('02/11/2019').replace(tzinfo=pytz.UTC)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.