Làm cách nào tôi có thể lọc ngày của DateTimeField trong Django?


173

Tôi đang cố gắng để DateTimeFieldso sánh với một ngày. Ý tôi là:

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

Tôi nhận được một danh sách truy vấn trống dưới dạng câu trả lời vì (tôi nghĩ) tôi không xem xét thời gian, nhưng tôi muốn "bất cứ lúc nào".

Có một cách dễ dàng trong Django để làm điều này?

Tôi có thời gian trong thời gian đã giải quyết, nó không phải là 00:00.


5
Đây là một trong những phiền toái của Django. Xem xét đây là một trường hợp sử dụng đơn giản và phổ biến, không có cách nào đơn giản để đạt được điều này.
rubayeet

Câu trả lời:


114

Tra cứu như vậy được thực hiện django.views.generic.date_basednhư sau:

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

Bởi vì nó khá dài dòng nên có kế hoạch cải thiện cú pháp bằng cách sử dụng __datetoán tử. Kiểm tra " # 9596 So sánh một DateTimeField với một ngày là quá khó " để biết thêm chi tiết.


4
Sử dụng với phạm vi: Q(created__gte=datetime.combine(created_value, time.min))
Dingo

10
Có vẻ như nó sẽ hạ cánh ở Django 1.9: github.com/django/django/commit/
mẹo

14
Mới trong Django 1.9:Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
Không phải

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

// chỉnh sửa sau khi bình luận

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

doest không hoạt động vì nó tạo ra một đối tượng datetime với giá trị thời gian được đặt thành 0, vì vậy thời gian trong cơ sở dữ liệu không khớp.


thx cho câu trả lời! sự thay thế đầu tiên không hoạt động với datetimefields. Công trình thay thế thứ hai;). Nếu ai đó biết phương pháp khác, vui lòng trả lời
Xidobix

docs.python.org/l Library / datetime.html#datetime- objects bằng cách sử dụng datetime () từ mô-đun datetime giờ, phút, giây là tùy chọn. thứ hai là từ một dự án đang hoạt động với các bình thay thế, bạn có thể xem các tài liệu đó là chính xác
zalew

Tôi biết đó là tùy chọn, vấn đề là datetimefield của tôi đã hết thời gian, không phải là 00:00
Xidobix

"sự thay thế đầu tiên không hoạt động với datetimefields." sẽ khá ngạc nhiên, vì datetime.datetime () trả về một đối tượng datetime djangoproject.com/documentation/0.96/models/basic kiểm tra định nghĩa mô hình và ví dụ: pub_date = model.DateTimeField () pub_date = datetime (2005, 7, 30)
zalew

"Tôi biết nó là tùy chọn, vấn đề là datetimefield của tôi đã hết thời gian, không phải là 00:00" Ồ, giờ tôi hiểu rồi. Có, không có đối số thời gian, nó đặt thành 00, vì vậy nó không quay trở lại :)
zalew

88

Dưới đây là kết quả tôi nhận được với chức năng timeit của 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

chứa dường như là nhanh hơn.


Giải pháp này dường như là gần đây nhất. Tôi ngạc nhiên khi nó nhận được 4 lượt upvote, vì khi tôi thử containsgiải pháp, tôi nhận được thông báo lỗi:Unable to get repr for <class 'django.db.models.query.QuerySet'>
Houman

Tôi kiểm tra lại và cập nhật kết quả ngày hôm nay và tôi không nghĩ lỗi của bạn là do __containsbộ lọc gây ra . Nhưng nếu bạn đang gặp vấn đề, bạn nên thử ví dụ tài liệu django đang sử dụng __gte.
Moreno

4
Phương thức __contains hoạt động tốt với tôi. Tôi nghĩ rằng đây có lẽ là câu trả lời tốt nhất vì nó cung cấp so sánh hiệu suất. Tôi đã bình chọn nhiều hơn một, nhưng tôi ngạc nhiên rằng nó không có nhiều sự ủng hộ hơn.
RobotHumans

Tôi thích startswithgiải pháp ..
w411 3

46

Bây giờ Django có bộ lọc truy vấn __date để truy vấn các đối tượng datetime theo ngày trong phiên bản phát triển. Vì vậy, nó sẽ có sẵn trong 1.9 sớm.


Vâng, nó đã được thêm vào 1.9 docs.djangoproject.com/en/1.9/ref/models/querysets/#date
guival

Câu trả lời hay nhất, hợp lệ cho các phiên bản Django mới hơn
serfer2

Đây không phải làm việc cho tôi, không biết tại sao :( Tôi đang trên django 1.11 ngoại lệ chính xác của tôi là: NotImplementedError: lớp con của basedatabaseoperations có thể đòi hỏi một phương pháp datetime_cast_date ()
AbdurRehman Khan

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

Trên đây là những gì tôi đã sử dụng. Nó không chỉ hoạt động, nó còn có một số hỗ trợ logic vốn có.


3
Tốt hơn nhiều so với tất cả các câu trả lời khác ở đây, cảm ơn!
Kin

sssss-shazam! 💯
DPS

30

Kể từ Django 1.9, cách để làm điều này là bằng cách sử dụng __datetrên một đối tượng datetime.

Ví dụ: MyObject.objects.filter(datetime_attr__date=datetime.date(2009,8,22))


27

Điều này tạo ra kết quả tương tự như sử dụng __year, __month và __day và dường như hoạt động với tôi:

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

19
có vẻ như điều này biến đối tượng ngày thành chuỗi và thực hiện so sánh chuỗi ngày do đó buộc db phải thực hiện quét toàn bộ bảng. đối với các bàn lớn, điều này sẽ giết chết màn trình diễn của bạn
yilmazhuseyin

8

giả sử active_on là một đối tượng ngày, tăng nó thêm 1 ngày sau đó thực hiện phạm vi

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

2

Đây là một kỹ thuật thú vị-- Tôi đã tận dụng thủ tục bắt đầu như được thực hiện với Django trên MySQL để đạt được kết quả là chỉ tìm kiếm một datetime chỉ qua ngày. Về cơ bản, khi Django thực hiện tra cứu trong cơ sở dữ liệu, nó phải thực hiện chuyển đổi chuỗi cho đối tượng lưu trữ MySQL củaETETIME, do đó bạn có thể lọc theo đó, bỏ phần dấu thời gian của ngày-- theo cách đó% THÍCH% chỉ khớp với ngày đối tượng và bạn sẽ nhận được mọi dấu thời gian cho ngày đã cho.

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

Điều này sẽ thực hiện các truy vấn sau đây:

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

BINary THÍCH trong trường hợp này sẽ khớp mọi thứ cho ngày, bất kể dấu thời gian. Bao gồm các giá trị như:

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

Hy vọng rằng điều này sẽ giúp tất cả mọi người cho đến khi Django đưa ra một giải pháp!


Ok, vì vậy đây có vẻ là câu trả lời tương tự như mhost và ấm đun nước ở trên, nhưng với nhiều mô tả hơn về những gì đang xảy ra trong phần phụ trợ. Ít nhất bạn có một lý do để sử dụng chứa hoặc bắt đầu cùng với thuộc tính date () của datetime!
bbengfort

2

Có một blogpost tuyệt vời bao gồm điều này ở đây: So sánh ngày và thời gian trong Django ORM

Giải pháp tốt nhất được đăng cho Django> 1.7, <1.9 là đăng ký một biến đổi:

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

Sau đó, bạn có thể sử dụng nó trong các bộ lọc của bạn như thế này:

Foo.objects.filter(created_on__date=date)

BIÊN TẬP

Giải pháp này chắc chắn là phụ thuộc vào cuối. Từ bài viết:

Tất nhiên, việc triển khai này phụ thuộc vào hương vị đặc biệt của SQL của bạn có hàm DATE (). MySQL nào. SQLite cũng vậy. Mặt khác, tôi đã không làm việc với cá nhân PostgreSQL, nhưng một số người làm cho tôi tin rằng nó không có chức năng DATE (). Vì vậy, việc thực hiện đơn giản này có vẻ như sẽ nhất thiết phải phụ thuộc vào phụ trợ.


MySQL này có cụ thể không? băn khoăn về sự lựa chọn tên lớp.
Binoj David

@BinojDavid Vâng, nó phụ thuộc vào phụ trợ
Dan Gayle

Tôi đã thử nghiệm nó bằng Django 1.8 và PostgreQuery 9.6.6 và nó hoạt động hoàn hảo. Trên thực tế, sử dụng PostgreSQL, bạn cũng có thể sử dụng cú pháp này:return '{}::date'.format(lhs), params
michal-michalak

1

Hừm .. Giải pháp của tôi đang hoạt động:

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


0

Trong Django 1.7.6 hoạt động:

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

2
Điều này chỉ hoạt động nếu bạn đang tìm kiếm ngày chính xác, bạn không thể sử dụng __lteví dụ.
guival

-1

Xem bài viết Tài liệu Django

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

5
trong tài liệu django nó hoạt động vì datetimefiled có thời gian 00:00
Xidobix
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.