私はDjango 5時間以上経過したウィジェットのクエリを作成しようとしていますが、少し迷っています。ウィジェットモデルにはDateTimeField
が入力されていますウィジェットの作成時間。
Widget
がモデルの名前であり、created
というDateTimeField属性がある場合、クエリは次のようになります。
from datetime import datetime, timedelta
time_threshold = datetime.now() - timedelta(hours=5)
results = Widget.objects.filter(created__lt=time_threshold)
ご了承ください created__lt
は、「作成されたものがより小さい」ことを意味します。
now = datetime.datetime.now()
earlier = now - datetime.timedelta(hours=5)
MyModel.objects.filter(my_date_field__range=(earlier,now))
これでうまくいくはずです。
settings.USE_TZ = Trueで、settings.TIME_ZONEが設定されている場合
from Django.utils import timezone
five_h_ago = timezone.now()-timezone.timedelta(hours=5)
example.object.filter(datetimefield__lt=five_h_ago)
最も単純なアプローチは、他の回答ですでに説明されています。日付が5時間前よりも前のレコードをフィルタリングするだけです。少なくとも5秒前に作成されたレコードを検索する完全な例を次に示します。
_# Tested with Django 1.11.15 and Python 3.6.
import logging
import sys
from datetime import datetime, timedelta
from time import sleep
import Django
from Django.apps import apps
from Django.apps.config import AppConfig
from Django.conf import settings
from Django.db import connections, models, DEFAULT_DB_ALIAS
from Django.db.models.base import ModelBase
NAME = 'udjango'
DB_FILE = NAME + '.db'
def main():
setup()
logger = logging.getLogger(__name__)
class Widget(models.Model):
name = models.CharField(max_length=200)
date_created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
syncdb(Widget)
Widget.objects.create(name='spline')
sleep(1)
Widget.objects.create(name='reticulator')
sleep(1)
Widget.objects.create(name='tardis')
sleep(5)
Widget.objects.create(name='sonic screwdriver')
sleep(1)
cutoff_time = datetime.now() - timedelta(seconds=5)
for widget in Widget.objects.filter(date_created__lt=cutoff_time):
logger.info(widget.name)
def setup():
with open(DB_FILE, 'w'):
pass # wipe the database
settings.configure(
DEBUG=True,
DATABASES={
DEFAULT_DB_ALIAS: {
'ENGINE': 'Django.db.backends.sqlite3',
'NAME': DB_FILE}},
LOGGING={'version': 1,
'disable_existing_loggers': False,
'formatters': {
'debug': {
'format': '[%(levelname)s]'
'%(name)s.%(funcName)s(): %(message)s',
'datefmt': '%Y-%m-%d %H:%M:%S'}},
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'debug'}},
'root': {
'handlers': ['console'],
'level': 'INFO'},
'loggers': {
"Django.db": {"level": "INFO"}}})
app_config = AppConfig(NAME, sys.modules['__main__'])
apps.populate([app_config])
Django.setup()
original_new_func = ModelBase.__new__
@staticmethod
def patched_new(cls, name, bases, attrs):
if 'Meta' not in attrs:
class Meta:
app_label = NAME
attrs['Meta'] = Meta
return original_new_func(cls, name, bases, attrs)
ModelBase.__new__ = patched_new
def syncdb(model):
""" Standard syncdb expects models to be in reliable locations.
Based on https://github.com/Django/django/blob/1.9.3
/Django/core/management/commands/migrate.py#L285
"""
connection = connections[DEFAULT_DB_ALIAS]
with connection.schema_editor() as editor:
editor.create_model(model)
main()
_
最後のウィジェット以外はすべて表示されます。
_[INFO]__main__.main(): spline
[INFO]__main__.main(): reticulator
[INFO]__main__.main(): tardis
_
タイムゾーンサポートを有効にしていない限り、これは正常に機能します。前の例では、_settings.configure(...
_を次のように変更することでそれを行っています。
_settings.configure(
USE_TZ=True,
...
_
そうすると、次のようなメッセージが表示されます。
_RuntimeWarning: DateTimeField Widget.date_created received a naive datetime (2019-01-07 16:39:04.563563) while time zone support is active.
_
タイムゾーン対応の日付を取得するには、timezone.now()
の代わりに datetime.now()
function を使用します。
_# Tested with Django 1.11.15 and Python 3.6.
import logging
import sys
from datetime import timedelta
from time import sleep
import Django
from Django.apps import apps
from Django.apps.config import AppConfig
from Django.conf import settings
from Django.db import connections, models, DEFAULT_DB_ALIAS
from Django.db.models.base import ModelBase
from Django.utils import timezone
NAME = 'udjango'
DB_FILE = NAME + '.db'
def main():
setup()
logger = logging.getLogger(__name__)
class Widget(models.Model):
name = models.CharField(max_length=200)
date_created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
syncdb(Widget)
Widget.objects.create(name='spline')
sleep(1)
Widget.objects.create(name='reticulator')
sleep(1)
Widget.objects.create(name='tardis')
sleep(5)
Widget.objects.create(name='sonic screwdriver')
sleep(1)
cutoff_time = timezone.now() - timedelta(seconds=5)
for widget in Widget.objects.filter(date_created__lt=cutoff_time):
logger.info(widget.name)
def setup():
with open(DB_FILE, 'w'):
pass # wipe the database
settings.configure(
USE_TZ=True,
DEBUG=True,
DATABASES={
DEFAULT_DB_ALIAS: {
'ENGINE': 'Django.db.backends.sqlite3',
'NAME': DB_FILE}},
LOGGING={'version': 1,
'disable_existing_loggers': False,
'formatters': {
'debug': {
'format': '[%(levelname)s]'
'%(name)s.%(funcName)s(): %(message)s',
'datefmt': '%Y-%m-%d %H:%M:%S'}},
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'debug'}},
'root': {
'handlers': ['console'],
'level': 'INFO'},
'loggers': {
"Django.db": {"level": "INFO"}}})
app_config = AppConfig(NAME, sys.modules['__main__'])
apps.populate([app_config])
Django.setup()
original_new_func = ModelBase.__new__
@staticmethod
def patched_new(cls, name, bases, attrs):
if 'Meta' not in attrs:
class Meta:
app_label = NAME
attrs['Meta'] = Meta
return original_new_func(cls, name, bases, attrs)
ModelBase.__new__ = patched_new
def syncdb(model):
""" Standard syncdb expects models to be in reliable locations.
Based on https://github.com/Django/django/blob/1.9.3
/Django/core/management/commands/migrate.py#L285
"""
connection = connections[DEFAULT_DB_ALIAS]
with connection.schema_editor() as editor:
editor.create_model(model)
main()
_
ときどき、データベースのクロックがWebサーバーのクロックと同期しなくなる問題が発生しました。この種の問題を回避するには、 Now()
function を使用して、データベースの現在の時刻を取得できます。
_# Tested with Django 1.11.15 and Python 3.6.
import logging
import sys
from datetime import timedelta
from time import sleep
import Django
from Django.apps import apps
from Django.apps.config import AppConfig
from Django.conf import settings
from Django.db import connections, models, DEFAULT_DB_ALIAS
from Django.db.models.base import ModelBase
from Django.db.models.functions import Now
from Django.utils import timezone
NAME = 'udjango'
DB_FILE = NAME + '.db'
def main():
setup()
logger = logging.getLogger(__name__)
class Widget(models.Model):
name = models.CharField(max_length=200)
date_created = models.DateTimeField()
def __str__(self):
return self.name
syncdb(Widget)
Widget.objects.create(name='spline', date_created=Now())
sleep(1)
Widget.objects.create(name='reticulator', date_created=Now())
sleep(1)
Widget.objects.create(name='tardis', date_created=Now())
sleep(5)
Widget.objects.create(name='sonic screwdriver', date_created=Now())
sleep(1)
cutoff_time = Now() - timedelta(seconds=5)
for widget in Widget.objects.filter(date_created__lt=cutoff_time):
logger.info(widget.name)
def setup():
with open(DB_FILE, 'w'):
pass # wipe the database
settings.configure(
USE_TZ=True,
DEBUG=True,
DATABASES={
DEFAULT_DB_ALIAS: {
'ENGINE': 'Django.db.backends.sqlite3',
'NAME': DB_FILE}},
LOGGING={'version': 1,
'disable_existing_loggers': False,
'formatters': {
'debug': {
'format': '[%(levelname)s]'
'%(name)s.%(funcName)s(): %(message)s',
'datefmt': '%Y-%m-%d %H:%M:%S'}},
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'debug'}},
'root': {
'handlers': ['console'],
'level': 'INFO'},
'loggers': {
"Django.db": {"level": "INFO"}}})
app_config = AppConfig(NAME, sys.modules['__main__'])
apps.populate([app_config])
Django.setup()
original_new_func = ModelBase.__new__
@staticmethod
def patched_new(cls, name, bases, attrs):
if 'Meta' not in attrs:
class Meta:
app_label = NAME
attrs['Meta'] = Meta
return original_new_func(cls, name, bases, attrs)
ModelBase.__new__ = patched_new
def syncdb(model):
""" Standard syncdb expects models to be in reliable locations.
Based on https://github.com/Django/django/blob/1.9.3
/Django/core/management/commands/migrate.py#L285
"""
connection = connections[DEFAULT_DB_ALIAS]
with connection.schema_editor() as editor:
editor.create_model(model)
main()
_
私は近年その問題を見ていないので、ほとんどの場合、面倒な価値はおそらくないでしょう。