Problem
For Django 1.1.
This is something I’ve included in my models. py:
class User(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
When I try to update a row, I get the following message:
[Sun Nov 15 02:18:12 2009] [error] /home/ptarjan/projects/twitter-meme/django/db/backends/mysql/base.py:84: Warning: Column 'created' cannot be null
[Sun Nov 15 02:18:12 2009] [error] return self.cursor.execute(query, args)
The following is a section of my database that is relevant:
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
Is this something to be concerned about?
A side question: those two fields aren’t shown in my admin tool. Is this to be expected?
Asked by Paul Tarjan
Solution #1
Any field that has the auto now attribute set inherits editable=False and hence does not appear in the admin interface. The auto now and auto now add parameters have been discussed in the past, and while they still exist, I believe you’re better off just using a custom save() function.
So, to make this work properly, I would recommend not using auto_now or auto_now_add and instead define your own save() method to make sure that created is only updated if id is not set (such as when the item is first created), and have it update modified every time the item is saved.
I’ve done exactly the same thing with other Django projects, so your save() function would look like this:
from django.utils import timezone
class User(models.Model):
created = models.DateTimeField(editable=False)
modified = models.DateTimeField()
def save(self, *args, **kwargs):
''' On save, update timestamps '''
if not self.id:
self.created = timezone.now()
self.modified = timezone.now()
return super(User, self).save(*args, **kwargs)
Hope this helps!
In response to feedback, I’ve made the following changes:
I stick with overloading save() rather than relying on these field arguments for two reasons:
To address why the OP saw the error, I don’t know exactly, but it looks like created isn’t even being populated at all, despite having auto_now_add=True. It stands out to me as a bug, and it emphasizes item #1 in my list above: auto_now and auto_now_add are flaky at best.
Answered by jathanism
Solution #2
However, I’d like to point out that the approved answer’s viewpoint is a little out of date. Auto now and auto now add aren’t going away, according to more recent debates (django bugs #7634 and #12785), and even if you go back to the initial conversation, you’ll find strong reasons against the RY (as in DRY) in custom save methods.
A better alternative (custom field types) has been proposed, but it hasn’t gained enough traction to be included in Django. You can write your own in three lines (as suggested by Jacob Kaplan-Moss).
from django.db import models
from django.utils import timezone
class AutoDateTimeField(models.DateTimeField):
def pre_save(self, model_instance, add):
return timezone.now()
#usage
created_at = models.DateField(default=timezone.now)
updated_at = AutoDateTimeField(default=timezone.now)
Answered by Shai Berger
Solution #3
To answer a side question, you may add readonly fields to your admin class to see these fields in admin (but you won’t be able to update them).
class SomeAdmin(ModelAdmin):
readonly_fields = ("created","modified",)
This, however, only applies to the most recent Django versions (I believe, 1.3 and above)
Answered by DataGreed
Solution #4
The simplest (and perhaps most elegant) option here, in my opinion, is to take advantage of the fact that you can set default to a callable. To avoid admin’s particular handling of auto now, simply specify the field as follows:
from django.utils import timezone
date_field = models.DateField(default=timezone.now)
It’s critical not to use timezone.now() because the default value will not update (i.e., default gets set only when the code is loaded). You might add a custom field if you find yourself doing this frequently. However, I believe this is already rather DRY.
Answered by Josh
Solution #5
If you change your model class as follows:
class MyModel(models.Model):
time = models.DateTimeField(auto_now_add=True)
time.editable = True
This field will then appear in my admin page’s change page.
Answered by Eric Zheng
Post is based on https://stackoverflow.com/questions/1737017/django-auto-now-and-auto-now-add