zoukankan      html  css  js  c++  java
  • 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;
    

    执行效果

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

  • 相关阅读:
    nginx的tcp/udp代理
    centos7的systemd服务详解
    centos7下ssh服务登陆认证详解
    laravel实现敏感词汇过滤
    laravel使用阿里云短信发送消息
    laravel中使用极光推送消息
    gitlab与jenkins结合构建持续集成
    gitlab的安装配置与简单使用
    centos7之firewalld防火墙的配置与使用
    使用码云,GitHub进行版本控制,并通过WebHook进行自动部署
  • 原文地址:https://www.cnblogs.com/yoyoketang/p/13209720.html
Copyright © 2011-2022 走看看