使用model_to_dict() 方法将 Model 模型对象转 dict 字典的时候,发现会漏掉 DateTimeField 字段
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的时候,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的日期时间字段
解决办法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