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

上一篇:TypeError: __init__() missing 1 required positional argument: 'on_delete' 解决办法


下一篇:PyTorch学习笔记 5.torchvision库