前言
使用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