Django model序列化为json的方法示例

作者:Van96 时间:2022-08-25 01:39:03 

本文环境

  • Python 3.6.5

  • Django 2.0.4

fix(2018.5.19):最近得知Django 的model基类需要声明为abstract,故在原来的代码加入abstract声明,以免误导

在Django中,关于如何将model类序列化为json,一般的话有两a器

将model类转为字典,再使用json库的dumps方法转为json

第一种方法就不多讲了,直接去看官方文档就好啦

一般来说,官方提供的方法应该都是比较好用和稳定的,然而,使用官方的序列化器却问题不少:

格式丑陋,格式如下,一言难尽:


[
 {
   "pk": "4b678b301dfd8a4e0dad910de3ae245b",
   "model": "sessions.session",
   "fields": {
     "expire_date": "2013-01-16T08:16:59.844Z",
     ...
   }
 }
]

是的,其中pk指的是默认主键,model指的是该object的model类型,然后fields才是obj的各种字段...真的是不知如何评价了

  • 不能很好地支持list

  • 对于一些外键(包括ManyToManyField等)不是很友好

  • 甚至对于自身的DateField也没有很好的支持

数了一通官方序列化器的缺点,当然了,上面的几个点肯定是有解决方案的,但是啊,我确实不想折腾了嘤嘤嘤。

于是扔出我的解决方案:

  • 新建一个类BaseModel,此类继承于官方的model类django.db.models.Model

  • 在着个BaseModel中,声明一个方法,此方法用于生成关于这个object的字典

  • 使用这个object的字典生成json

关于生成object的字典的策略是这样的:

  • 通过反射获取这个object的所有字段名

  • 根据字段名获得某个字段field

  • 如果filed的类型的是int、float、str的话,直接将以 "字段名":字段值 的形式放入字典中

  • 若field的类型是datetime或者date的话,使用date的方式处理,然后放入字典

  • 若field的类型是BaseModel的话,那么就调用该field的getDict方法递归获得该field对应的字典,然后放入字典中

  • 若field的类型是ManyToMany类型,在具体草种中我们使用这个field的all方法来这个field的所有object,然后也是通过getDict方法将其放入到字典中

源码及使用方法


from django.db import models
import json

class BaseModel(models.Model):
 class Meta:
   abstract = True

# 返回self._meta.fields中没有的,但是又是需要的字段名的列表
 # 形如['name','type']
 def getMtMField(self):
   pass

# 返回需要在json中忽略的字段名的列表
 # 形如['password']
 def getIgnoreList(self):
   pass

def isAttrInstance(self, attr, clazz):
   return isinstance(getattr(self, attr), clazz)

def getDict(self):
   fields = []
   for field in self._meta.fields:
     fields.append(field.name)

d = {}
   import datetime
   for attr in fields:
     if isinstance(getattr(self, attr), datetime.datetime):
       d[attr] = getattr(self, attr).strftime('%Y-%m-%d %H:%M:%S')
     elif isinstance(getattr(self, attr), datetime.date):
       d[attr] = getattr(self, attr).strftime('%Y-%m-%d')
     # 特殊处理datetime的数据
     elif isinstance(getattr(self, attr), BaseModel):
       d[attr] = getattr(self, attr).getDict()
     # 递归生成BaseModel类的dict
     elif self.isAttrInstance(attr, int) or self.isAttrInstance(attr, float) \
         or self.isAttrInstance(attr, str):
       d[attr] = getattr(self, attr)
     # else:
     #   d[attr] = getattr(self, attr)

mAttr = self.getMtMField()
   if mAttr is not None:
     for m in mAttr:
       if hasattr(self, m):
         attlist = getattr(self, m).all()
         l = []
         for attr in attlist:
           if isinstance(attr, BaseModel):
             l.append(attr.getDict())
           else:
             dic = attr.__dict__
             if '_state' in dic:
               dic.pop('_state')
             l.append(dic)
         d[m] = l
   # 由于ManyToMany类不能存在于_meat.fields,因而子类需要在getMtMFiled中返回这些字段
   if 'basemodel_ptr' in d:
     d.pop('basemodel_ptr')

ignoreList = self.getIgnoreList()
   if ignoreList is not None:
     for m in ignoreList:
       if d.get(m) is not None:
         d.pop(m)
   # 移除不需要的字段
   return d

def toJSON(self):
   import json
   return json.dumps(self.getDict(), ensure_ascii=False).encode('utf-8').decode()

使用方法:

models的所有类都继承BaseModel类,然后调用此类的toJSON()方法即可

注意,不知为何,self._meta.fields中没有包含ManyToManyField字段,因而需要重写getMtMField方法。例子如下:


class Book(BaseModel):
 name = models.CharField(max_length=50)
 authors = models.ManyToManyField(Author)
 publish = models.ForeignKey(Publisher, on_delete=models.SET_NULL, blank=True, null=True)
 page = models.IntegerField(default=0) # 页数
 introduction = models.CharField(max_length=500)
 bookType = models.ManyToManyField(BookType, null=True, blank=True)
 bookTag = models.ManyToManyField(BookTag, null=True, blank=True)
 evaluation = models.FloatField()
 coverUrl = models.CharField(max_length=100, null=True, blank=True)

def getMtMField(self):
   return ['bookType', 'bookTag']

结果:


{
 "id":4,
 "name":"Django从入门到放弃",
 "page":123,
 "introduction":"introduction",
 "evaluation":1,
 "bookType":[
   {
     "id":1,
     "name":"类型"
   }
 ],
 "bookTag":[
   {
     "id":2,
     "name":"tag"
   }
 ]
}

后记

源码有引用,即getDict方法中的第一个for循环,但懒得找原链接了,望见谅,特此声明;

  • 本人python新手,代码多有不规范之处,望见谅;

  • 代码不精,但是也希望能帮到你_;

来源:https://www.jianshu.com/p/c3db3cc2c80a

标签:Django,model,json
0
投稿

猜你喜欢

  • PHP用Session实现用户登陆功能

    2023-06-18 02:09:38
  • js对象基础实例分析

    2023-09-03 12:07:56
  • js关于 byval 与 byref 的区别

    2007-10-13 10:48:00
  • 使用C#配合ArcGIS Engine进行地理信息系统开发

    2023-06-25 16:35:01
  • Python 查看list中是否含有某元素的方法

    2023-07-29 21:46:08
  • python中list.copy方法用法详解

    2023-09-16 11:48:30
  • python中类的属性和方法介绍

    2023-10-22 05:14:47
  • python检索特定内容的文本文件实例

    2022-12-29 12:05:42
  • JavaScript事件冒泡

    2009-12-28 13:21:00
  • Dreamweaver快速编辑网页标签

    2009-05-29 18:35:00
  • 浅谈python中的面向对象和类的基本语法

    2023-06-27 11:36:45
  • JavaScript+canvas实现七色板效果实例

    2023-08-09 09:48:10
  • python 实现的发送邮件模板【普通邮件、带附件、带图片邮件】

    2023-10-07 00:52:22
  • Asp中如何快速分页的技巧

    2008-05-17 12:02:00
  • 一文带你掌握Python中文词频统计

    2022-11-17 21:02:00
  • Python压缩解压缩zip文件及破解zip文件密码的方法

    2023-04-20 10:30:30
  • 下载golang.org/x包的操作方法

    2023-07-11 16:54:04
  • 浅谈视觉设计的准确性

    2007-09-18 17:59:00
  • web2.0中流行的设计元素:颜色

    2007-12-10 12:16:00
  • PHP入门教程之会话控制技巧(cookie与session)

    2023-11-16 00:13:39
  • asp之家 网络编程 m.aspxhome.com