DjangoでDateTimeFieldの日付をフィルタリングするにはどうすればよいですか?


173

DateTimeField日付との比較をフィルタリングしようとしています。というのは:

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

私は時間を考慮していない(と思う)ため、空のクエリセットリストを回答として取得しますが、「いつでも」欲しいのです。

これを行う簡単な方法はDjangoにありますか?

設定された日時に時刻がありますが、そうではありません00:00


5
これはDjangoの問題の1つです。これが単純で一般的な使用例であることを考えると、これを達成する簡単な方法はありません。
rubayeet

回答:


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

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

時間値が0に設定されたdatetimeオブジェクトを作成し、データベース内の時間が一致しないため、機能しません。


答えはTHX!最初の選択肢は、datetimefieldsでは機能しません。2番目の代替案は機能します;)。誰かが別の方法を知っている場合は答えてください
Xidobix 2009

docs.python.org/library/datetime.html#datetime-objects datetime()をdatetimeモジュールから使用するhrs、mins、secsはオプションです。2つ目は、varsが置き換えられた作業プロジェクトからのものです。正しいドキュメントを見ることができます
zalew

私はそれがオプションであることを知っています、問題は私のdatetimefieldに時刻が設定されていることです、それは00:00ではありません
Xidobix

「最初の選択肢は、datetimefieldsでは機能しません。」datetime.datetimeの()はDateTimeオブジェクトを返すように、それは、非常に驚くべきだろうdjangoproject.com/documentation/0.96/models/basic PUB_DATE = models.DateTimeField()PUB_DATE =日時を(2005、7:モデル定義および例をチェック30)
zalew 2009

「私はそれがオプションであることを知っています。問題は、私のdatetimefieldに時刻が設定されていることです。それは00:00ではありません」ああ、今それを取得します。はい、時間引数なしで00に設定されるため、返されません:)
zalew

88

ここに私がipythonのtimeit関数で得た結果があります:

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
モレノ

4
__containsメソッドは私にとってはうまく機能します。パフォーマンスの比較ができるので、これがおそらく最良の答えだと思います。私は複数投票しましたが、それ以上の投票がないことに驚きました。
RobotHumans 2013年

私は大好きstartswithソリューション...
w411 3

46

Djangoには、開発バージョンの日付に対してdatetimeオブジェクトをクエリする__date querysetフィルターがあります。したがって、1.9でまもなく利用可能になります。



ベストアンサー、新しいDjangoバージョンに有効
serfer2

これは私には機能しません、理由はわかりません:(私はdjango 1.11を使用しています。私の正確な例外は次のとおりです:NotImplementedError:basedatabaseoperationsのサブクラスはdatetime_cast_date()メソッドを必要とする可能性があります
AbdurRehman Khan

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

上記は私が使用したものです。機能するだけでなく、固有の論理的裏付けもあります。


3
ここの他のすべての答えよりもはるかに良いです、ありがとう!
キン

sssss-shazam!💯–
dps

30

Django 1.9以降、これを行う方法は__date、日時オブジェクトで使用することです。

例えば: MyObject.objects.filter(datetime_attr__date=datetime.date(2009,8,22))


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

これは興味深い手法です。MySQLのDjangoで実装されたstartswithプロシージャを利用して、日付のみを介して日時のみを検索する結果を達成しました。基本的に、Djangoがデータベースでルックアップを行う場合は、DATETIME MySQLストレージオブジェクトの文字列変換を行う必要があるため、日付のタイムスタンプ部分を除外してフィルタリングできます。これにより、%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が解決策を発表するまで、これがすべての人に役立ちます!


OK、これは上記のmhostおよびKettlehellと同じ答えであるように見えますが、バックエンドで何が起こっているかについての詳細な説明があります。少なくとも、日付時刻のdate()属性とともに、containsまたはstartswithを使用する理由があります!
bbengfort 2012

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)

編集

このソリューションは間違いなくバックエンドに依存しています。記事から:

もちろん、この実装は、DATE()関数を持つSQLの特定の種類に依存しています。MySQLにはあります。SQLiteも同様です。一方、私はPostgreSQLを個人的に操作したことはありませんが、グーグル操作を行うと、それがDATE()関数を持たないものと思われます。したがって、この単純な実装は、バックエンドに依存する必要があるようです。


これはMySQL固有ですか?クラス名の選択について疑問に思っています。
Binoj David、2015

@BinojDavidええ、それはバックエンドに依存しています
Dan Gayle

Django 1.8とPostgreSQL 9.6.6を使用してテストしたところ、問題なく動作しました。:実はあなたもこの構文を使用することができますPostgreSQLの使用return '{}::date'.format(lhs), params
ミハル-michalak

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 2016

-1

Djangoのドキュメントを参照してください。

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

5
djangoのドキュメントでは、datetimefiledの時刻が00:00であるため機能します
Xidobix
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.