I have a model like this:
class FooBar(models.Model):
createtime = models.DateTimeField(auto_now_add=True)
lastupdatetime = models.DateTimeField(auto
You can't really disable auto_now/auto_now_add in another way than you already do. If you need the flexibility to change those values, auto_now
/auto_now_add
is not best choice. It is often more flexible to use default
and/or override the save()
method to do manipulation right before the object is saved.
Using default
and an overridden save()
method, one way to solve your problem would be to define your model like this:
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)
In your code, where you want to skip the automatic lastupdatetime change, just use
new_entry.save(skip_lastupdatetime=True)
If your object is saved in the admin interface or other places, save() will be called without the skip_lastupdatetime argument, and it will behave just as it did before with auto_now
.
I went the context manager way for reusability.
@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']
Use like so:
with suppress_autotime(my_object, ['updated']):
my_object.some_field = some_value
my_object.save()
Boom.
I needed to disable auto_now for a DateTime field during a migration and was able to do this.
events = Events.objects.all()
for event in events:
for field in event._meta.fields:
if field.name == 'created_date':
field.auto_now = False
event.save()
I've recently faced this situation while testing my application. I needed to "force" an expired timestamp. In my case I did the trick by using a queryset update. Like this:
# 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.
A bit more clean version of context manager from https://stackoverflow.com/a/35943149/1731460
from contextlib import contextmanager
@contextmanager
def suppress_auto_now(model, field_names):
"""
idea taken here https://stackoverflow.com/a/35943149/1731460
"""
fields_state = {}
for field_name in field_names:
field = model._meta.get_field(field_name)
fields_state[field] = {'auto_now': field.auto_now, 'auto_now_add': field.auto_now_add}
for field in fields_state:
field.auto_now = False
field.auto_now_add = False
try:
yield
finally:
for field, state in fields_state.items():
field.auto_now = state['auto_now']
field.auto_now_add = state['auto_now_add']
You can use it even with Factories (factory-boy)
with suppress_autotime(Click, ['created']):
ClickFactory.bulk_create(post=obj.post, link=obj.link, created__iter=created)
copy of Django - Models.DateTimeField - Changing dynamically auto_now_add value
Well , I spent this afternoon find out and the first problem is how fetch model object and where in code . I'm in restframework in serializer.py , for example in __init__
of serializer it could not have the Model yet . Now in to_internal_value you can get the model class , after get the Field and after modify the field properties like in this example :
class ProblemSerializer(serializers.ModelSerializer):
def to_internal_value(self, data):
ModelClass = self.Meta.model
dfil = ModelClass._meta.get_field('date_update')
dfil.auto_now = False
dfil.editable = True