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, instead of using auto now or auto now add, I would consider defining your own save() function to ensure that created is only changed if id is not set (such as when the item is first created) and that modified is updated 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 answer why the OP received the problem, I’m not sure, but it appears that created isn’t getting populated at all, even when auto now add=True is set. It stands out to me as a bug, and it emphasizes item #1 in my list above: At best, auto now and auto now add are shaky.
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
Talking about a side question: if you want to see this fields in admin (though, you won’t be able to edit it), you can add readonly_fields to your admin class.
class SomeAdmin(ModelAdmin):
readonly_fields = ("created","modified",)
Well, this applies only to latest 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