一、自定义数据类型
背景:想在模型上添加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()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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}
可是模型中常见的日期类型没有时间戳格式?首先需求上是否需要时间戳?这个字段是与业务不相关的,主要是记录该数据的变化情况,设置成时间戳反而不易阅读,如果确实需要可以再自己转换。
如果非要时间戳记录创建时间和更新时间也不是不可以,简单的看了下其他数据类型的源码后,不如自己仿着别的造一个数据类型
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
至此,写个脚本自测一下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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文件,应该改成下面
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
标签:int,auto,add,ORM,time,82,Model,now,True From: https://www.cnblogs.com/YK2012/p/16837433.html