打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
python测试开发django-77.ORM如何添加 DateTimeField 不显示毫秒

前言

使用 django 的 orm 建模型的时候,添加 DateTimeField 字段,发现存到数据库的日期时间格式是’2020-06-28 21:30:48.481516’
我们一般习惯的格式是’2020-06-28 21:30:48’不带后面的6位数毫秒
参考stackoverflow链接:https://stackoverflow.com/questions/46539755/how-to-add-datetimefield-in-django-without-microsecond
环境:

  • django 2

  • mysql 5.7

问题描述

model 模型是这样写的

class People(models.Model):
name = models.CharField(max_length=20)
age = models.IntegerField()
create_time = models.DateTimeField()

class Meta:
db_table = "people"

同步数据库后,表里面的字段类型如下

mysql> desc people;
+-------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(20) | NO | | NULL | |
| age | int(11) | NO | | NULL | |
| create_time | datetime(6) | NO | | NULL | |
+-------------+-------------+------+-----+---------+----------------+

Django 创建的 datetime 字段是带有6位数的毫秒的

datetime(6)

我们期望的是 datetime 在同步数据库的时候应该不带毫秒

datetime()

解决办法

这是一个非常有趣的问题。我查看了源代码,下面是用小数秒设置日期时间的原因,找到源码的位置django/db/backends/mysql/base.py

class DatabaseWrapper(BaseDatabaseWrapper):
vendor = 'mysql'
# This dictionary maps Field objects to their associated MySQL column
# types, as strings. Column-type strings can contain format strings; they'll
# be interpolated against the values of Field.__dict__ before being output.
# If a column type is set to None, it won't be included in the output.
_data_types = {
'AutoField': 'integer AUTO_INCREMENT',
'BinaryField': 'longblob',
'BooleanField': 'bool',
'CharField': 'varchar(%(max_length)s)',
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
'DateField': 'date',
'DateTimeField': 'datetime',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'DurationField': 'bigint',
'FileField': 'varchar(%(max_length)s)',
'FilePathField': 'varchar(%(max_length)s)',
'FloatField': 'double precision',
'IntegerField': 'integer',
'BigIntegerField': 'bigint',
'IPAddressField': 'char(15)',
'GenericIPAddressField': 'char(39)',
'NullBooleanField': 'bool',
'OneToOneField': 'integer',
'PositiveIntegerField': 'integer UNSIGNED',
'PositiveSmallIntegerField': 'smallint UNSIGNED',
'SlugField': 'varchar(%(max_length)s)',
'SmallIntegerField': 'smallint',
'TextField': 'longtext',
'TimeField': 'time',
'UUIDField': 'char(32)',
}

@cached_property
def data_types(self):
if self.features.supports_microsecond_precision:
return dict(self._data_types, DateTimeField='datetime(6)', TimeField='time(6)')
else:
return self._data_types

# ... further class methods

data_types 方法中在进行 MySQL 版本检查,属性supports_microsecond_precision来自于文件django/db/backends/mysql/features.py:

class DatabaseFeatures(BaseDatabaseFeatures):
# ... properties and methods

def supports_microsecond_precision(self):
# See https://github.com/farcepest/MySQLdb1/issues/24 for the reason
# about requiring MySQLdb 1.2.5
return self.connection.mysql_version >= (5, 6, 4) and Database.version_info >= (1, 2, 5)

所以如果使用的 MySQL 大于等于 5.6.4 版本,属性DateTimeField会被映射成为数据库中的datetime(6),所以保存的数据就包含了微秒。
在 Django 中暂时没有发现可以针对改配置进行设置的方法,所以最后用了猴子补丁(monkey-patching):

from django.db.backends.mysql.base import DatabaseWrapper

DatabaseWrapper.data_types = DatabaseWrapper._data_types

将上面的代码放置在合适的地方,比如models.py或者init.py或者其他地方,当我们运行 migrations 命令来创建 DateTimeField 列的时候对应在数据库中的字段就被隐射成为了datetime,而不是datetime(6),即使你用的是 5.6.4 版本以上的数据库。

强制修改表

上面的猴子补丁(monkey-patching)对于已存到数据库的数据是没法修改的,如果是已经建表并且有数据了,需执行SQL修改表。
你想立即解决这个问题,数据库的日期时间字段 datetime(6) 强制修改成 datetime()即可

ALTER TABLE `yoyo_card` CHANGE COLUMN `add_time` `add_time` datetime NOT NULL;

执行效果


当然这只是一个临时解决方案

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
如何快速安全的插入千万条数据?
Django之 Models组件
django forms DateTimeField
peewee与mysql的使用
SUN JDO+DataNucleus+mysql配置
myeclipse开发hibernate应用程序示例
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服