Django查询日期时间大于5小时的对象


70

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

Answers:


157

如果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意味着“创建的内容少于”。


1
如果hours来自表列而不是硬编码值,我们将如何实现相同的目的?
adkl

这是否将过滤创建的记录> 5小时(创建的时间超过5小时?)
Grant Gubatan '18年

@GrantGubatan不完全:__lt代表“小于”,因此它正在筛选时间戳小于或等于五个小时前的记录
大卫·罗宾逊

1
如果您的DateTimeField使用auto_now,则其值将由数据库服务器设置。在datetime.now() - timedelta(hours=5)将数据库客户端,这可能不是对应于数据库服务器的时间来计算。如何使记录的寿命完全在数据库服务器上计算?
JoeMjr2

4
如果TZ支持活动时,使用from django.utils import timezonetimezone.now()代替datetime.now()
达斯汀·米歇尔斯

18
now = datetime.datetime.now()
earlier = now - datetime.timedelta(hours=5)
MyModel.objects.filter(my_date_field__range=(earlier,now))

这应该够了吧。


6
超过5小时,不少于5小时!
大卫·罗宾逊

5
范围的东西虽然有用。
radtek

11

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

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()function而不是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()

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


-1

如果您想超过5小时,请使用created__gte代替created__lt


这个帖子看起来不完整,为什么?“获得超过...”是什么意思?
蚊蚋

@gnat我在回复要求增加5小时以上年龄的人
Feysal
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.