24

I would like a timestamp field updating each time the record is modified like in MySQL.

DateTimeField(default=datetime.datetime.now()) will only set it the first time it is created...

Any have a simple solution? Is the only solution is to manually set the Column options in MySQL db?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Xelt
  • 406
  • 3
  • 9

4 Answers4

39

You can override the save method on your model class.

class Something(Model):
    created = DateTimeField(default=datetime.datetime.now)
    modified = DateTimeField

    def save(self, *args, **kwargs):
        self.modified = datetime.datetime.now()
        return super(Something, self).save(*args, **kwargs)
coleifer
  • 24,887
  • 6
  • 60
  • 75
  • 1
    Please advise how to do same for updates e.g., Something.update(othercolumn=foo).where(id=2).execute(). Or do I need to rewrite my code to use Model.save() instead? Thx in advance. – chrisinmtown Mar 07 '15 at 13:01
  • 2
    If you're calling `.update()` then you may need to implement the timestamp updating logic on the SQL side. `update()` does not call `save()`. – coleifer Mar 08 '15 at 16:21
  • Is there a way to override the Model class in Peewee? – Jeff Oct 16 '15 at 12:56
  • 1
    Jeff, Peewees models are just regular classes. You can subclass them (Ie create a BaseModel with various default fields, helper functions, etc). – Shayne Jul 06 '18 at 09:01
4

Just use TIMESTAMP type in MySQL. This field will update itself whenever the row is updated.

In the model:

last_updated = peewee.TimestampField()
ATOzTOA
  • 34,814
  • 22
  • 96
  • 117
  • Any tips for how I can do this for Postgresql? – Kyrremann Sep 25 '18 at 20:34
  • This is incorrect. This will store the current utc timestamp on create, but will NOT update it when the row is modified (unless you define an `ON UPDATE` constraint) – booshong Nov 04 '20 at 07:50
1

You can also override the update method to provide.Just like what coleifer do:

class Something(Model):
    created = DateTimeField(default=datetime.datetime.now)
    modified = DateTimeField

    @classmethod
    def update(cls, *args, **kwargs):
        kwargs['modified'] = datetime.datetime.now()
        return super(Something, cls).save(*args, **kwargs)

    def save(self, *args, **kwargs):
        self.modified = datetime.datetime.now()
        return super(Something, self).save(*args, **kwargs)

You can also do the same thing on replace method

leo zheng
  • 29
  • 1
  • Bad idea. The SQL-generation methods should never be overridden (update, insert, select, etc). – coleifer Dec 27 '18 at 20:09
  • I would argue that if the logic is complex enough, adding it into such a "pre-save" step is acceptable. You just need to make sure you enforce using the right methods when CRUDing objects (e.g. `update()` and `delete()` should be avoided). – booshong Nov 04 '20 at 07:35
1
from datetime import datetime

from peewee import (AutoField, CharField, DateTimeField, FloatField,
                    IntegerField, Model, MySQLDatabase, TextField, SQL)

from config import DataBaseConfig

mysql_client = MySQLDatabase(
    "your_database_name",
    host=DataBaseConfig.host,
    port=DataBaseConfig.port,
    user=DataBaseConfig.user,
    password=DataBaseConfig.password,
)

class CommonModel(Model):
    id = AutoField(verbose_name="primary key")
    create_time = DateTimeField(default=datetime.now, verbose_name="create time")
    update_time = DateTimeField(default=datetime.now, verbose_name="update time", constraints=[SQL('ON UPDATE CURRENT_TIMESTAMP')])

    class Meta:
        database = mysql_client

You can refer to this document. Single-column indexes and constraints!

forever.m
  • 11
  • 1