Django 的序列化操作

发布于 2024-07-16 05:39:01 字数 9301 浏览 17 评论 0

关于对数据表记录进行序列化的过程作了一些尝试,又要能把整个记录序列化,又希望中文能正常显示,走了一些弯路,终于得到结果,下面是目前最理想的方式。

Django 中提供了一个 serializers 可以对 Django 中 Model 的数据进行序列化和反序列化的操作,可以很方便的将数据库中的数据转换成 jsonxml 格式,以方便进一步的数据交换或转存等操作。

askingRecord 数据表为例

1. 序列化:

>>> from django.core import serializers

>>> # 这是一个 model,已有数据,可做测试
>>> from task.models import TaskingRecord

>>> se = json.dumps(json.loads(serializers.serialize('json',TaskingRecord.objects.all()[:1])), ensure_ascii=False)
>>> se
'[{"model": "task.taskingrecord", "fields": {"report_time": "2016-10-10T15:37:26.593Z",
"is_pass": true, "review": "", "cause": "", "is_onsite": true, "processer": null,
"is_resolved": true, "curlink": 0, "deal": "", "reporter": 4, "symptom": "",
"problem": "Office 无法打开 docx 文档。"}, "pk": 1}]'

序列化达到我们的要求, json 格式,中文正常显示
为了测试反序列化我们对序列化文本做了修改来测试序列化后的文本是否能够正常恢复

>>> se = '[{"model": "task.taskingrecord", "fields": {"report_time": "2016-10-10T15:37:26.593Z",
"is_pass": true, "review": "可以再试看看", "cause": "没原因没道理", "is_onsite": true,
"processer": null, "is_resolved": true, "curlink": 0, "deal": "安啦 hehe",
"reporter": 4, "symptom": "", "problem": "Office 无法打开 docx 文档。"}, "pk": 1}]'

2. 反序列化:

>>> for dso in serializers.deserialize('json',se):
... dso.save() # save() 执行后即把反序列后的恢复到原数据表原记录中

我们再提取保存后的数据看看结果

>>> json.dumps(json.loads(serializers.serialize('json',TaskingRecord.objects.all()[:1])), ensure_ascii=False)
'[{"model": "task.taskingrecord", "fields": {"report_time": "2016-10-10T15:37:26.593Z",
"is_pass": true, "review": "可以再试看看", "cause": "没原因没道理", "is_onsite": true,
"processer": null, "is_resolved": true, "curlink": 0, "deal": "安啦 hehe",
"reporter": 4, "symptom": "", "problem": "Office 无法打开 docx 文档。"}, "pk": 1}]'

重新提取后发现修改后的内容确实有更新到数据表中

重点提示:

序列化:对数据表记录进行序列化后,就可以把记录内容备份到指定文本字段中或文件中用于备份;
反序列化:把保存在文本字段或文件中的文本反序列化,并加以保存,即恢复原备份数据到原来的记录中;

这两个操作用于数据记录做历史保存和数据恢复尤其有用。

  • json.loads() :将 json 文本 str 转换成列表 obj
  • json.dumps() :将 json 列表 obj 转换为文本 str

===================下面是之前尝试的过程,仅供参考===============

1. 序列化

Django 的序列化操作,将记录序列化为文本

from django.core import serializers
serializers.serialize(“json”, queryset)
需要注意的是这里序列化的只能是 queryset,它是一个列表,而不应该是实例,直白一点就是只能是 filter(),而不能用 get()。

下面是序列化的测试:

>>> from django.core import serializers

>>> # 这是一个 model,已有数据,可做测试
>>> from task.models import TaskingRecord

>>> # 取前两个记录的一个 queryset,即一个列表
>>> data = TaskingRecord.objects.all()[:2]
>>> data
[<TaskingRecord: 李四: 1234 - Office 无法打开 docx 文档。>, <TaskingRecord: 李四: 1234 - 电脑无法启动>]

>>> serializers.serialize("json", data)
'[{"model": "task.taskingrecord", "pk": 1, "fields": {"reporter": 4,
"curlink": 0, "problem": "Office\\u65e0\\u6cd5\\u6253\\u5f00docx\\u6587\\u6863\\u3002",
"report_time": "2016-10-10T15:37:26.593Z", "processer": null, "symptom": "",
"cause": "", "deal": "", "is_onsite": true, "is_resolved": true, "is_pass": true, "review": ""}},
{"model": "task.taskingrecord", "pk": 2, "fields": {"reporter": 4, "curlink": 0,
"problem": "\\u7535\\u8111\\u65e0\\u6cd5\\u542f\\u52a8", "report_time": "2016-10-10T15:41:55.537Z", "processer": null, "symptom": "",
"cause": "", "deal": "", "is_onsite": true, "is_resolved": true, "is_pass": true, "review": ""}}]'

>>> # 如果用 get() 方式
>>> data1=TaskingRecord.objects.get(pk=2)
>>> # 获得的是一个实例
>>> data1
<TaskingRecord: 李四: 1234 - 电脑无法启动>

>>> # 对实例进行序列化就会报错
>>> serializers.serialize("json", data1)
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "/home/snail/e3se/lib/python3.5/site-packages/django/core/serializers/__init__.py", line 129, in serialize
s.serialize(queryset, **options)
File "/home/snail/e3se/lib/python3.5/site-packages/django/core/serializers/base.py", line 79, in serialize
for count, obj in enumerate(queryset, start=1):
TypeError: 'TaskingRecord' object is not iterable

>>> # 这里需要再次强调的是 get() 返回的是一个实例,而 filter() 返回的是一个 queryset(),即一个列表
>>> # 有两种解决方案,个人建议可以使用第一种
>>> # 第一种是将实例列表化
>>> data1=TaskingRecord.objects.get(pk=2)
>>> [data1]
[<TaskingRecord: 李四: 1234 - 电脑无法启动>]
>>> serializers.serialize("json", [data1])
'[{"model": "task.taskingrecord", "pk": 2, "fields": {"reporter": 4,
"curlink": 0, "problem": "\\u7535\\u8111\\u65e0\\u6cd5\\u542f\\u52a8",
"report_time": "2016-10-10T15:41:55.537Z", "processer": null, "symptom": "",
"cause": "", "deal": "", "is_onsite": true, "is_resolved": true, "is_pass": true, "review": ""}}]'

>>> # 第二种方法是使用 filter() 来获取。
>>> data1=TaskingRecord.objects.filter(pk=2)
>>> data1
[<TaskingRecord: 李四: 1234 - 电脑无法启动>]
>>> serializers.serialize("json", data1)
'[{"model": "task.taskingrecord", "pk": 2, "fields": {"reporter": 4,
"curlink": 0, "problem": "\\u7535\\u8111\\u65e0\\u6cd5\\u542f\\u52a8",
"report_time": "2016-10-10T15:41:55.537Z", "processer": null, "symptom": "", "cause": "",
"deal": "", "is_onsite": true, "is_resolved": true, "is_pass": true, "review": ""}}]'

2. 反序列化

有序列化就有反序列化,反序列化即把序列化的文本恢复为反序列化对象,关键是这个对象是可以保存回原表记录的哦。

>>> # 比如有一个序列化文本
>>> serial_data
'[{"model": "task.taskingrecord", "pk": 7, "fields": {"reporter": 1,
"curlink": 0, "problem": "\\u8981\\u6c42\\u91cd\\u65b0\\u5b89\\u88c5\\u7cfb\\u7edf",
"report_time": "2016-10-11T13:04:36.505Z", "processer": null, "symptom": "",
"cause": "", "deal": "", "is_onsite": true, "is_resolved": true, "is_pass": true, "review": ""}}]'
>>> data = serializers.deserialize('json',serial_data)
>>> data
<generator object Deserializer at 0x7f0b0f98fbf8>
>>> for deserialized_object in serializers.deserialize("json", serial_data):
... if object_should_be_saved(deserialized_object):
... # 这个反序列化对象在你需要时是可以通过 save() 方法来保存到数据库的
... deserialized_object.save()

这里还有另一个问题,序列化文本的中文显示问题

3. 序列化文件的中文显示

上述方式适合做为数据交换,因为不存在文本编码的问题,但是如果我们是做为记录备份,保存到一个 TEXT 字段中的话,我们就希望能看得清楚字段的内容,毕竟可能还需要做后继的处理,如果字段内容都看不明白,就谈不上不后继操作了。其实最简单的方式是把是上述的 json 格式改为 xml 就可以了。
如上述的序列化改为

>>> se = serializers.serialize("xml", [data1])
>>> se
'<?xml version="1.0" encoding="utf-8"?>\n<django-objects version="1.0">
<object model="task.taskingrecord" pk="2">
<field name="reporter" rel="ManyToOneRel" to="task.reporter">4</field>
<field name="curlink" type="SmallIntegerField">0</field>
<field name="problem" type="CharField">电脑无法启动</field>
<field name="report_time" type="DateTimeField">2016-10-10T15:41:55.537483+00:00</field>
<field name="processer" rel="ManyToOneRel" to="auth.user"><None></None></field>
<field name="symptom" type="CharField"></field>
<field name="cause" type="CharField"></field>
<field name="deal" type="CharField"></field>
<field name="is_onsite" type="BooleanField">True</field>
<field name="is_resolved" type="BooleanField">True</field>
<field name="is_pass" type="BooleanField">True</field>
<field name="review" type="CharField"></field></object></django-objects>'

这样序列化后的文本就可以很方便的保存到如 log 的操作记录表的 Text 字段里了
同样的,反序列化改为

>>> serializers.deserialize("xml", se)
<generator object Deserializer at 0x7f0dbc34efc0>

如果我们需要恢复历史记录到原数据表,只需要读取 log 的相应的历史记录的 Text 字段,然后如下执行,就可以把数据恢复回原数据表了。

>>> for dso in serializers.deserialize("json", se):
... # 这个反序列化对象在你需要时是可以通过 save() 方法来保存到数据库的
... dso.save()

注:用 json 适合交换,如果不考虑中文问题,也适合保存,但也因为中文加码了,不方便查看内容,因此不适合用在这里的备份;用 python 格式也可以显示中文,但序列化后是一个 List ,而我们保存到记录里的是 TEXT 字段的,因此貌似用 xml 更合适。

Django 中可以在 Models.py 中定义:

class TaskingRecord(models.Model):  # 报修工单
...
def to_xml(self):
return serializers.serialize("xml", [self])
to_xml.short_description = '序列化文本'

在数据保存前先行判断是否有 changed ,有则保存 to_xml 字段的值到 log 数据表,就可以达到备份记录的目的。

可以另起两个字段保存 model 名和 pk 号就更完整了。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

我的奇迹

暂无简介

0 文章
0 评论
23 人气
更多

推荐作者

玍銹的英雄夢

文章 0 评论 0

我不会写诗

文章 0 评论 0

十六岁半

文章 0 评论 0

浸婚纱

文章 0 评论 0

qq_kJ6XkX

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文