我有这样的模型:
class FooBar(models.Model):
createtime = models.DateTimeField(auto_now_add=True)
lastupdatetime = models.DateTimeField(auto_now=True)
Run Code Online (Sandbox Code Playgroud)
我想覆盖一些模型实例的两个日期字段(在迁移数据时使用).目前的解决方案如下:
for field in new_entry._meta.local_fields:
if field.name == "lastupdatetime":
field.auto_now = False
elif field.name == "createtime":
field.auto_now_add = False
new_entry.createtime = date
new_entry.lastupdatetime = date
new_entry.save()
for field in new_entry._meta.local_fields:
if field.name == "lastupdatetime":
field.auto_now = True
elif field.name == "createtime":
field.auto_now_add = True
Run Code Online (Sandbox Code Playgroud)
有更好的解决方案吗?
dir*_*rls 91
我最近在测试我的应用程序时遇到了这种情况.我需要"强制"过期的时间戳.在我的情况下,我通过使用查询集更新来完成这个技巧.像这样:
# my model
class FooBar(models.Model):
title = models.CharField(max_length=255)
updated_at = models.DateTimeField(auto_now=True, auto_now_add=True)
# my tests
foo = FooBar.objects.get(pk=1)
# force a timestamp
lastweek = datetime.datetime.now() - datetime.timedelta(days=7)
FooBar.objects.filter(pk=foo.pk).update(updated_at=lastweek)
# do the testing.
Run Code Online (Sandbox Code Playgroud)
and*_*lme 52
你不能以另一种方式禁用auto_now/auto_now_add.如果您需要灵活地更改这些值,auto_now/ auto_now_add不是最佳选择.在保存对象之前,使用default和/或覆盖save()方法来进行操作通常更灵活.
使用default和重写save()方法,解决问题的一种方法是定义您的模型,如下所示:
class FooBar(models.Model):
createtime = models.DateTimeField(default=datetime.datetime.now)
lastupdatetime = models.DateTimeField()
def save(self, *args, **kwargs):
if not kwargs.pop('skip_lastupdatetime', False):
self.lastupdatetime = datetime.datetime.now()
super(FooBar, self).save(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
在您的代码中,您想跳过自动lastupdatetime更改,只需使用
new_entry.save(skip_lastupdatetime=True)
Run Code Online (Sandbox Code Playgroud)
如果您的对象保存在管理界面或其他位置,则会在没有skip_lastupdatetime参数的情况下调用save(),并且它将像以前一样运行auto_now.
Fra*_*ard 25
我使用了提问者提出的建议,并创建了一些功能.以下是用例:
turn_off_auto_now(FooBar, "lastupdatetime")
turn_off_auto_now_add(FooBar, "createtime")
new_entry.createtime = date
new_entry.lastupdatetime = date
new_entry.save()
Run Code Online (Sandbox Code Playgroud)
这是实施:
def turn_off_auto_now(ModelClass, field_name):
def auto_now_off(field):
field.auto_now = False
do_to_model(ModelClass, field_name, auto_now_off)
def turn_off_auto_now_add(ModelClass, field_name):
def auto_now_add_off(field):
field.auto_now_add = False
do_to_model(ModelClass, field_name, auto_now_add_off)
def do_to_model(ModelClass, field_name, func):
field = ModelClass._meta.get_field_by_name(field_name)[0]
func(field)
Run Code Online (Sandbox Code Playgroud)
可以创建类似的功能以重新打开它们.
Apo*_*ata 19
如果您知道要将哪些字段限制为并且排除auto_now/auto_now_add字段,也可以使用该update_fields参数save():
https://docs.djangoproject.com/en/stable/ref/models/instances/#specifying-which-fields-to-save
sou*_*kah 17
我采用了上下文管理器的方式来实现可重用性.
@contextlib.contextmanager
def suppress_autotime(model, fields):
_original_values = {}
for field in model._meta.local_fields:
if field.name in fields:
_original_values[field.name] = {
'auto_now': field.auto_now,
'auto_now_add': field.auto_now_add,
}
field.auto_now = False
field.auto_now_add = False
try:
yield
finally:
for field in model._meta.local_fields:
if field.name in fields:
field.auto_now = _original_values[field.name]['auto_now']
field.auto_now_add = _original_values[field.name]['auto_now_add']
Run Code Online (Sandbox Code Playgroud)
使用如下:
with suppress_autotime(my_object, ['updated']):
my_object.some_field = some_value
my_object.save()
Run Code Online (Sandbox Code Playgroud)
繁荣.
对于那些在编写测试时看到这个的人,有一个叫做freezegun的python库可以让你伪造时间 - 所以当auto_now_add代码运行时,它会得到你真正想要的时间.所以:
from datetime import datetime, timedelta
from freezegun import freeze_time
with freeze_time('2016-10-10'):
new_entry = FooBar.objects.create(...)
with freeze_time('2016-10-17'):
# use new_entry as you wish, as though it was created 7 days ago
Run Code Online (Sandbox Code Playgroud)
它也可以用作装饰器 - 请参阅上面的基本文档链接.
您auto_now_add无需特殊代码即可覆盖。
当我尝试创建具有特定日期的对象时遇到了这个问题:
Post.objects.create(publication_date=date, ...)
Run Code Online (Sandbox Code Playgroud)
哪里publication_date = models.DateField(auto_now_add=True)。
所以这就是我所做的:
post = Post.objects.create(...)
post.publication_date = date
post.save()
Run Code Online (Sandbox Code Playgroud)
这已成功覆盖auto_now_add.
作为一个更长期的解决方案,覆盖save方法是要走的路:https : //code.djangoproject.com/ticket/16583
| 归档时间: |
|
| 查看次数: |
21879 次 |
| 最近记录: |