zoukankan      html  css  js  c++  java
  • python测试开发django-119.model_to_dict会漏掉DateTimeField字段

    前言

    使用model_to_dict() 方法将 Model 模型对象转 dict 字典的时候,发现会漏掉 DateTimeField 字段

    model_to_dict()

    Model模型

    # 作者-上海悠悠 QQ交流群:717225969
    # blog地址 https://www.cnblogs.com/yoyoketang/
    
    class Teacher(models.Model):
        """老师表"""
        name = models.CharField(max_length=30)
        age = models.IntegerField(blank=True, null=True)
        tel = models.CharField(max_length=30)
        is_delete = models.CharField(max_length=10, default=0, blank=True)
        add_time = models.DateTimeField(auto_now_add=True,
                                        verbose_name="添加时间")
    
        def __str__(self):
            return self.name
    

    查询结果转dict类型

    >python manage.py shell
    Python 3.6.6 (v3.6.6:4cf1f54eb7, Jun 27 2018, 03:37:03) [MSC v.1900 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    (InteractiveConsole)
    >>> from yoyo.models import Teacher
    >>> Teacher.objects.filter(name='悠悠老师').values()
    <QuerySet [{'id': 2, 'name': '悠悠老师', 'age': 22, 'tel': '21122121', 'is_delete': '0', 'add_time': datetime.datetime(2021, 9, 8, 0, 0, tzinfo=<UTC>)}]>
    >>>
    >>>
    >>> a = Teacher.objects.filter(name='悠悠老师')[0]
    >>> a
    <Teacher: 悠悠老师>
    >>> from django.forms.models import model_to_dict
    >>> model_to_dict(a)
    {'id': 2, 'name': '悠悠老师', 'age': 22, 'tel': '21122121', 'is_delete': '0'}
    

    .values()方法可以转QuerySet对象,里面是会有add_time字段的,但是用model_to_dict方法转Teacher对象的时候,
    结果返回{'id': 2, 'name': '悠悠老师', 'age': 22, 'tel': '21122121', 'is_delete': '0'},缺少了add_time日期时间字段

    auto_now_add 为True

    当设置auto_now_add = True的时候,DateTimeField会把editable属性设置为False,并且把blank设置为True

    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)
    

    再看model_to_dict()函数的源码内容

    def model_to_dict(instance, fields=None, exclude=None):
        """
        Return a dict containing the data in ``instance`` suitable for passing as
        a Form's ``initial`` keyword argument.
    
        ``fields`` is an optional list of field names. If provided, return only the
        named.
    
        ``exclude`` is an optional list of field names. If provided, exclude the
        named from the returned dict, even if they are listed in the ``fields``
        argument.
        """
        opts = instance._meta
        data = {}
        for f in chain(opts.concrete_fields, opts.private_fields, opts.many_to_many):
            if not getattr(f, 'editable', False):
                continue
            if fields and f.name not in fields:
                continue
            if exclude and f.name in exclude:
                continue
            data[f.name] = f.value_from_object(instance)
        return data
    

    主要看这句if not getattr(f, 'editable', False)如果字段的editable属性为False那么就跳过,所以会导致漏掉auto_now, auto_now_add为True的日期时间字段

    解决办法to_dict()

    解决办法1:可以不要设置auto_now, auto_now_add为True,给个default默认当前时间,这种治标不治本,改起来麻烦。
    解决办法2:自己重写一个转dict的方法

    在Teacher模型添加一个to_dict()方法,把对象转成字段,并且把日期时间格式也转成自己喜欢的格式

    # 作者-上海悠悠 QQ交流群:717225969
    # blog地址 https://www.cnblogs.com/yoyoketang/
    
    class Teacher(models.Model):
        """老师表"""
        name = models.CharField(max_length=30)
        age = models.IntegerField(blank=True, null=True)
        tel = models.CharField(max_length=30)
        is_delete = models.CharField(max_length=10, default=0, blank=True)
        add_time = models.DateTimeField(auto_now_add=True,
                                        verbose_name="添加时间")
    
        def __str__(self):
            return self.name
    
        def to_dict(self):
            """重写model_to_dict()方法转字典"""
            from datetime import datetime
    
            opts = self._meta
            data = {}
            for f in opts.concrete_fields:
                value = f.value_from_object(self)
                if isinstance(value, datetime):
                    value = value.strftime('%Y-%m-%d %H:%M:%S')
                elif isinstance(f, models.FileField):
                    value = value.url if value else None
                data[f.name] = value
            return data
    

    这样就能完美解决日期时间问题,调用也方便

    >python manage.py shell
    Python 3.6.6 (v3.6.6:4cf1f54eb7, Jun 27 2018, 03:37:03) [MSC v.1900 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    (InteractiveConsole)
    >>> from yoyo.models import Teacher
    >>> a = Teacher.objects.filter(name='悠悠老师')[0]
    >>> a.to_dict()
    {'id': 2, 'name': '悠悠老师', 'age': 22, 'tel': '21122121', 'is_delete': '0', 'add_time': '2021-09-08 00:00:00'}
    >>>
    

    参考博客https://www.jianshu.com/p/a491d35a878b

  • 相关阅读:
    centos7 killall 命令
    移动硬盘拒绝访问问题解决方法
    Linux实现内容分发的主备模式的智能DNS
    UWB DWM1000 跟随小车原理--- 原理代码解析
    DWM1000 自动应答代码实现与实例
    UWB DWM1000 跟随小车原理---一张图演示
    DWM1000 帧过滤代码实现
    Bphero-UWB 基站0 和 电脑串口数据格式定义
    DW1000 用户手册中文版 附录3:双向测距(Two-Way Ranging)
    DW1000 用户手册中文版 附录2 IEEE-802.15.4 MAC层
  • 原文地址:https://www.cnblogs.com/yoyoketang/p/15244171.html
Copyright © 2011-2022 走看看