Automatically changing Django model field on update for one field and freezing one-time write-only for another?

Question:

Is there a onupdate parameter for Django’s model fields?

For example, in Flask with SQLAlchemy, it’s possible to do something like the following with the onupdate=... parameter for the database schema’s db.Column():

import datetime

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    created_on = db.Column(db.Text, default=datetime.datetime.utcnow().isoformat())
    updated_on = db.Column(db.Text, default=datetime.datetime.utcnow().isoformat(), 
                           onupdate=datetime.datetime.utcnow().isoformat())

From the docs, there’s an auto_now parameter, is that the same thing as the onupdate=... parameter in in SQLAlchemy’s db.Column()

I’ve tried the following model object to emulate the Flask’s code above but how could I get the same onupdate=... “effect” in Django?

from django.db import models
from django.utils.timezone import now

class User(models.Model):
    id = models.IntegerField()
    created_on = models.DateTimeField(default=now)
    updated_on = models.DateTimeField(default=now)
    name = models.CharField(default='blah blah')

How do I “freeze” the value for the create_on field such that it can only be added once and never to be changed again afterwards?

But for the updated_on, it changes every time I change the values of the User, e.g. if I created a User and save, then change the name afterwards, created_on should remain the same but updated_on is automatically updated?

Asked By: alvas

||

Answers:

In django you have the auto_now_add and auto_now optional arguments for models.DateTimeField

class User(models.Model):
    id = models.IntegerField()
    created_on = models.DateTimeField(auto_now_add=True)
    updated_on = models.DateTimeField(auto_now=True)
    name = models.CharField(default='blah blah')

auto_now_add will set the field to the current time when an object is created and auto_now will set the field to the current time when an object is created or updated. You should be aware of some quirky behaviour though:

The field is only automatically updated when calling Model.save(). The field isn’t updated when making updates to other fields in other ways such as QuerySet.update(), though you can specify a custom value for the field in an update like that.

More info in the docs at https://docs.djangoproject.com/en/1.9/ref/models/fields/#datetimefield and https://docs.djangoproject.com/en/1.9/ref/models/fields/#django.db.models.DateField

Answered By: A. J. Parr
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.