专栏首页从零开始学自动化测试python测试开发django-77.ORM如何添加 DateTimeField 不显示毫秒

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;

执行效果

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

本文分享自微信公众号 - 从零开始学自动化测试(yoyoketang),作者:上海悠悠

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-06-30

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Appium+python自动化20-查看iOS上app元素属性

    前言 学UI自动化首先就是定位页面元素,玩过android版的appium小伙伴应该都知道,appium的windows版自带的Inspector可以定位app...

    上海-悠悠
  • Appium+python自动化55-Unlock和Appium Setting

    部分真机可能会出现每次运行代码,启动app之前都会重复安装Unlock和Appium Setting这两个小工具,有的手机会自动安装,这个还好。 有的手机每次都...

    上海-悠悠
  • python测试开发django-65.序列化(ModelSerializer)

    serializers.Serializer可以对modle模型中的字段序列化,并且必须写create和update两个方法。ModelSerializer可以...

    上海-悠悠
  • python: time模块、datetime模块

    JNingWei
  • 一日一技:装饰器如何装饰异步函数

    在 Python 开发的工程中,我们常常使用装饰器来优化代码,例如一个打印日志的装饰器:

    青南
  • Unity Procedural Level Generator 基础总结与功能优化

    Procedural Level Generator是在Unity应用商店中发布的一款免费的轻量级关卡生成器:

    汐夜koshio
  • HDU 1052 Tian Ji -- The Horse Racing(贪心)

    Enterprise_
  • 作死作死,完美主义,又“重写”了

    后来发现执行脚本变动比较频繁,需要反复执行dos转换为unix,于是做了一个DojobH,即支持脚本——包装了3条固定操作:

    刘娟娟PRESSone
  • 自动化生成报表

    利用 info() 方法查看数据中是否有空值,如果有空值的话,则可以使用 dropna() 方法将其移除。

    zucchiniy
  • Android如何调用so文件

    下面通过一个安卓调用C++代码打印字符串的实例介绍一下在Android Studio中使用最新的编译方式编译出so文件的步骤。

    用户5521279

扫码关注云+社区

领取腾讯云代金券