饮冰三年-人工智能-Django淘宝拾遗-82-ORM之Model篇

一、自定义数据类型

背景:想在模型上添加create_time_int和update_time_int用于记录数据新增和更新时间,

要求新增的时候,modify_time_int和 create_time_int一致,后面更新时该条记录modify_time_int更新为当前时间,create_time_int保持不变。格式为时间:eg:1666958153

分析:我们都知道django中给我们提供了多种时间相关的数据类型,但是时间戳格式的确实没有,所以我们不妨重写save(),在数据保存的时候直接给modify_time_int赋值。

1:重写save()

class Publication(models.Model):
    title = models.CharField(max_length=30)
    # django 中常见的日期类型,注意 auto_now 与 auto_now_add
    add_date = models.DateField(blank=True, null=True, auto_now_add=True, verbose_name='创建日期', help_text='创建日期')
    add_time = models.TimeField(blank=True, null=True, auto_now_add=True, verbose_name='创建时间', help_text='创建时间')
    add_date_time = models.DateTimeField(blank=True, null=True, auto_now_add=True, verbose_name='创建时间')
    # 通过设置默认值的方式设置时间
    add_time_int = models.IntegerField(verbose_name="创建时间戳", default=int(time.time()))
    # 通过自定义数据类型方式设置时间
    add_time_stamp = TimeStampField(verbose_name="创建时间戳", auto_now_add=True)

    modify_date = models.DateField(blank=True, null=True, auto_now=True, verbose_name='修改日期', help_text='修改日期')
    modify_time = models.TimeField(blank=True, null=True, auto_now=True, verbose_name='修改时间', help_text='修改时间')
    modify_date_time = models.DateTimeField(blank=True, null=True, auto_now=True, verbose_name='修改时间', )
    # 通过设置默认值的方式设置时间
    modify_time_int = models.IntegerField(verbose_name="修改时间戳", )
    # 通过自定义数据类型方式设置时间
    modify_time_stamp = TimeStampField(verbose_name="修改时间戳", auto_now=True)

    class Meta:
        ordering = ['title']
        managed = True
        db_table = 'tb_publication'
        verbose_name = '出版社'

    def save(self, *args, **kwargs):
        self.modify_time_int = int(time.time())  # 自动更新时间
        super(Publication, self).save(*args, **kwargs)

    def __str__(self):
        return self.title
模型代码

在实际生产中发现有些数据update_time_int为空,后来分析发现这些数据通过bulk_create()创建,

原来 save() 方法在create()中会调用,在批量创建bulk_create()并不会调用

其实django中大家通用的方法是用(时间格式+auto_now属性)控制【更新时间】,(auto_now_add)属性控制【创建时间】。

模型中常见的日期类型有 {DateField:2022-10-28, TimeField:11:33:06.368256, DateTimeField:2022-10-28 11:33:06.368256+08} 

可是模型中常见的日期类型没有时间戳格式?首先需求上是否需要时间戳?这个字段是与业务不相关的,主要是记录该数据的变化情况,设置成时间戳反而不易阅读,如果确实需要可以再自己转换。

如果非要时间戳记录创建时间和更新时间也不是不可以,简单的看了下其他数据类型的源码后,不如自己仿着别的造一个数据类型

class TimeStampField(IntegerField):
    description = "TimeStampField integer"
    MAX_BIGINT = 9223372036854775807

    def __init__(self, verbose_name=None, name=None, auto_now=False,
                 auto_now_add=False, **kwargs):
        self.auto_now, self.auto_now_add = auto_now, auto_now_add
        if auto_now or auto_now_add:
            kwargs['editable'] = False
            kwargs['blank'] = True
        super().__init__(verbose_name, name, **kwargs)

    def pre_save(self, model_instance, add):
        if self.auto_now or (self.auto_now_add and add):
            value = int(time.time())
            setattr(model_instance, self.attname, value)
            return value
        else:
            return super().pre_save(model_instance, add)
TimeStampField

至此,写个脚本自测一下

import datetime
import os

import django

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'DRF.settings')
django.setup()

from api_service.report.models import Publication


# 创建记录会有数据
def add_publication():
    pub_dict = {
        "title": "单个创建"
    }
    Publication.objects.create(**pub_dict)


def add_publications():
    pub_list = []
    pub_dict = {
        "title": "批量创建1"
    }
    pub_dict2 = {
        "title": "批量创建2"
    }
    pub_list.append(Publication(**pub_dict))
    pub_list.append(Publication(**pub_dict2))
    Publication.objects.bulk_create(pub_list)


def update_publication():
    pub_query_set = Publication.objects.filter(id=1)
    for pub in pub_query_set:
        pub = pub  # type Publication
        pub.title = "修改"
        pub.save()


def update_publication_s():
    Publication.objects.filter(id__in=(4, 5)).update(title="修改后")


# obj, created = Person.objects.get_or_create(first_name='John', last_name='Lennon',
# defaults={'birthday': 1})

# add_publication()
"""结论:单个创建一切正常"""
# add_publications()
"""结论:批量创建一切正常"""
# update_publication()
"""结论:修改的时候modify_time_int没有修改,这就是default的特性"""
update_publication_s()
"""结论:批量修改的时候所有modify没有修改"""
View Code

 

 

 彩蛋

create的时候 auto_now 在什么时候触发?
django.db.models.sql.compiler.SQLInsertCompiler.as_sql
django.db.models.sql.compiler.SQLInsertCompiler.pre_save_val ps:从给定obj中获取给定字段的值。pre_save()用于DateTimeField上的auto_now。
django.db.models.fields.DateField.pre_save 这里面会判断 auto_now
auto_now:在数据经过Model层更新时会自动触发,如果用django filter的update(通常为批量更新数据时)则是因为直接调用sql语句 不通过 model层
auto_now_add:只在数据创建时添加,在数据更新时不变

还有朋友说:“简单直接方法是--直接modify_time_int一个默认值。” 单从结果上来看也是一个不错的建议。

另外默认值处不要这样写

add_time_int = models.IntegerField(verbose_name="创建时间戳", default=int(time.time()))

 这种会在每次makemigrations时候更行migrate文件,应该改成下面

def current_time():
    return int(time.time())


class Publication(models.Model):
    title = models.CharField(max_length=30)
    # 通过这方式设置默认时间
    add_time_int = models.IntegerField(verbose_name="创建时间戳", default=current_time)
   
View Code

 

posted @ 2022-10-29 09:07  逍遥小天狼  阅读(39)  评论(0编辑  收藏  举报