80

我正在尝试为超过 5 小时的小部件编写 Django 查询,但我有点迷路了。小部件模型有一个DateTimeField填充了小部件创建时间的值。

4

5 回答 5

174

如果Widget是您的模型的名称,并且它有一个名为的 DateTimeField 属性created,则查询将是:

from datetime import datetime, timedelta

time_threshold = datetime.now() - timedelta(hours=5)
results = Widget.objects.filter(created__lt=time_threshold)

请注意,这created__lt意味着“创建小于”。

于 2012-04-27T05:27:32.567 回答
19
now = datetime.datetime.now()
earlier = now - datetime.timedelta(hours=5)
MyModel.objects.filter(my_date_field__range=(earlier,now))

这应该够了吧。

于 2012-04-27T05:30:57.563 回答
13

如果 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)
于 2018-10-16T05:54:50.360 回答
1

其他答案已经涵盖了最简单的方法:只需过滤日期早于五个小时前的记录。下面是一个完整的示例,它查找至少五秒前创建的记录:

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

# 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()函数获取数据库中的当前时间。

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

近年来我没有看到这个问题,所以在大多数情况下可能不值得麻烦。

于 2019-01-08T00:56:41.597 回答
-1

如果您想超过 5 小时,请使用created__gte而不是created__lt

于 2019-06-13T08:04:12.313 回答