如何在 django 中执行与此 SQL 等效的操作?
UPDATE table SET timestamp=NOW() WHERE ...
特别是我想使用服务器的内置函数设置日期时间字段,以从运行数据库的服务器获取系统时间,而不是客户端计算机上的时间。
我知道您可以直接执行原始sql,但我正在寻找更便携的解决方案,因为数据库具有不同的函数来获取当前日期时间。我会避免使用 auto_now 参数,因为它会在每次修改时设置新的时间戳,同时我想在特定实例上执行此操作。
正如 j0ker 所说,如果你想自动更新时间戳,请使用
auto_now
选项。例如。 date_modified = models.DateTimeField(auto_now=True)
。
如果您想仅在首次创建对象时将字段设置为现在,您应该使用:
date_modified = models.DateTimeField(auto_now_add=True)
或者如果你想手动完成,用python 不就是简单的赋值吗
datetime.now()
?
from datetime import datetime
obj.date_modified = datetime.now()
接受的答案已过时。这是当前最简单的方法:
>>> from django.utils import timezone
>>> timezone.now()
datetime.datetime(2018, 12, 3, 14, 57, 11, 703055, tzinfo=<UTC>)
从 Django 1.9 开始,您可以使用数据库功能Now:
from django.db.models.functions import Now
Model.objects.filter(...).update(timestamp=Now())
这是我解决这个问题的方法。希望它可以节省某人的时间:
from django.db import models
class DBNow(object):
def __str__(self):
return 'DATABASE NOW()'
def as_sql(self, qn, val):
return 'NOW()', {}
@classmethod
def patch(cls, field):
orig_prep_db = field.get_db_prep_value
orig_prep_lookup = field.get_prep_lookup
orig_db_prep_lookup = field.get_db_prep_lookup
def prep_db_value(self, value, connection, prepared=False):
return value if isinstance(value, cls) else orig_prep_db(self, value, connection, prepared)
def prep_lookup(self, lookup_type, value):
return value if isinstance(value, cls) else orig_prep_lookup(self, lookup_type, value)
def prep_db_lookup(self, lookup_type, value, connection, prepared=True):
return value if isinstance(value, cls) else orig_db_prep_lookup(self, lookup_type, value, connection=connection, prepared=True)
field.get_db_prep_value = prep_db_value
field.get_prep_lookup = prep_lookup
field.get_db_prep_lookup = prep_db_lookup
# DBNow Activator
DBNow.patch(models.DateTimeField)
然后只需使用 DBNow() 作为需要更新和过滤的值:
books = Book.objects.filter(created_on__gt=DBNow())
or:
book.created_on = DBNow()
book.save()
您可以使用类似这样的方法来创建自定义值来表示数据库上当前时间的使用:
class DatabaseDependentValue(object):
def setEngine(self, engine):
self.engine = engine
@staticmethod
def Converter(value, *args, **kwargs):
return str(value)
class DatabaseNow(DatabaseDependentValue):
def __str__(self):
if self.engine == 'django.db.backends.mysql':
return 'NOW()'
elif self.engine == 'django.db.backends.postgresql':
return 'current_timestamp'
else:
raise Exception('Unimplemented for engine ' + self.engine)
django_conversions.update({DatabaseNow: DatabaseDependentValue.Converter})
def databaseDependentPatch(cls):
originalGetDbPrepValue = cls.get_db_prep_value
def patchedGetDbPrepValue(self, value, connection, prepared=False):
if isinstance(value, DatabaseDependentValue):
value.setEngine(connection.settings_dict['ENGINE'])
return value
return originalGetDbPrepValue(self, value, connection, prepared)
cls.get_db_prep_value = patchedGetDbPrepValue
然后能够在 DateTimeField 上使用 DatabaseNow:
databaseDependentPatch(models.DateTimeField)
这最终可以让你做得又漂亮又干净:
class Operation(models.Model):
dateTimeCompleted = models.DateTimeField(null=True)
# ...
operation = # Some previous operation
operation.dateTimeCompleted = DatabaseNow()
operation.save()
我调整后的代码适用于 sqlite、mysql 和 postgresql,并且比建议的解决方案更干净。
class DBCurrentTimestamp:
def __str__(self):
return 'DATABASE CURRENT_TIMESTAMP()'
def as_sql(self, qn, connection):
return 'CURRENT_TIMESTAMP', {}
@classmethod
def patch(cls, *args):
def create_tweaked_get_db_prep_value(orig_get_db_prep_value):
def get_db_prep_value(self, value, connection, prepared=False):
return value if isinstance(value, cls) else orig_get_db_prep_value(self, value, connection, prepared)
return get_db_prep_value
for field_class in args:
field_class.get_db_prep_value = create_tweaked_get_db_prep_value(field_class.get_db_prep_value)
我在 models.py 文件末尾激活它,如下所示:
DBCurrentTimestamp.patch(models.DateField, models.TimeField, models.DateTimeField)
并像这样使用它:
self.last_pageview = DBCurrentTimestamp()
我创建了一个 Python Django 插件模块,它允许您控制
CURRENT_TIMESTAMP
对象上 DateTimeField
的使用,无论是在特定情况下(参见下面的 usage
),还是自动控制 auto_now
和 auto_now_add
列。
django-pg-当前时间戳
GitHub:https://github.com/jaytaylor/django-pg-current-timestamp
PyPi:https://pypi.python.org/pypi/django-pg-current-timestamp
使用示例:
from django_pg_current_timestamp import CurrentTimestamp
mm = MyModel.objects.get(id=1)
mm.last_seen_date = CurrentTimestamp()
mm.save()
## Resulting SQL:
## UPDATE "my_model" SET "last_seen_date" = CURRENT_TIMESTAMP;
print MyModel.objects.filter(last_seen_date__lt=CURRENT_TIME).count()
MyModel.objects.filter(id__in=[1, 2, 3]).update(last_seen_date=CURRENT_TIME)
如果您想要来自外部服务器(即,不是托管 Django 应用程序的服务器)的日期时间,则必须手动将其固定为要使用的数据时间。您可以使用 SQL 命令,例如
select now();
或通过 SSH 的命令,例如 ssh user@host "date +%s"
。
也许你应该看看文档:
模型字段:日期字段
“auto_now”选项可能正是您正在寻找的。您还可以将其与 DateTimeField 一起使用。每次保存模型时它都会更新日期时间。因此,为 DateTimeField 设置该选项后,检索数据记录并再次保存以设置正确的时间就足够了。
创建表格时,添加数据后要在字段中设置日期的字段将此代码添加到字段中
class MyModel(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)