RESTful Web Services——1:序列化和反序列化

导读:本篇文章讲解 RESTful Web Services——1:序列化和反序列化,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

目前的项目结构:
在这里插入图片描述

目的:

  • 设计RESTful Web服务以与简单的SQLite数据库进行交互——对实体资源执行CRUD操作。
  • 定义Web服务的需求,并了解每种HTTP方法和不同执行范围。
  • 在Django中执行迁移以在数据库中创建所需的表来表示和持久化实体资源。
  • 学习如何使用Django REST framework实现实体资源的序列化为和反序列化。

1,定义相关需求

假设一个开发团队正在开发适用于 iOS 和 Android 移动应用程序,并且需要RESTful Web服务来对实体执行CRUD操作。
但绝对不想使用模拟Web服务,也不想花时间选择和配置ORM,而是希望快速构建一个RESTful Web服务,并使其尽快准备好开始在移动应用程序中与之交互。尽管不需要将其投入生产环境,但希望实体资源够保存在最简单的关系数据库中。

Django REST framework配合Django默认的SQLite数据库将使我们能够轻松完成这些任务。

现在开始我们的RESTful Web 服务的第一个版本。

首先,我们必须指定资源实体的要求,用以下属性或字段来描述一个toy实体:

  • 一个唯一标识符
  • 一个名称
  • 一个详情描述
  • 一个分类信息
  • 一个表示玩具是否在在线商店的商店主页中存在的布尔值
  • 一个包含玩具添加的日期和时间时间戳

在RESTful理念中,使用唯一 URI标识每个资源,我们将使用HTTP的统一接口。下面是用到的方法、使用范围和方法语义:

HTTP方法 作用范围 语义 描述
GET 单个实体资源 查询单个玩具信息 http://localhost:8000/toys/{id} 查询单个玩具信息
GET 实体资源集合 查询所有玩具信息 http://localhost:8000/toys/ 查询所有玩具信息
POST 实体资源集合 创建一个玩具信息 使用JSON格式提交请求到http://localhost:8000/toys/以创建新toy。服务器将验证它是否为有效的toy,是则将其保留在数据库中,并返回201 Created状态代码和相关的JSON正文。
PUT 单个实体资源 修改一个玩具信息 使用JSON格式提交HTTP请求到http://localhost:8000/toys/{id}以更改toy信息,成功则返回200 OK状态代码和JSON正文;如果没有为新toy提供所有必要的数据,则返回400 Bad Request状态代码;如果服务器找不到具有指定 ID 的toy,则仅返回404 Not Found状态码。
DELETE 单个实体资源 删除一个玩具信息 使用JSON格式提交HTTP请求到http://localhost:8000/toys/{id}以删除toy信息,成功则返回204 OK状态代码;如果服务器找不到具有指定 ID 的toy,则返回404 Not Foundt状态代码。

2,创建模型

描述一个toy实体:

toys/models.py:

from django.db import models
class Toy(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    name = models.CharField(max_length=150, blank=False, default='')
    description = models.CharField(max_length=250, blank=True, default='')
    toy_category = models.CharField(max_length=200, blank=False, default='')
    release_date = models.DateTimeField()
    was_included_in_home = models.BooleanField(default=False)
    
    class Meta:
        ordering = ('name',) 
        
    def __str__(self):
        return self.name
  • 非常重要的是,模型默认会将未定义的 id 映射为 pk

3,数据迁移

使用settings.py中默认数据库配置:

DATABASES = {
	'default': {
		'ENGINE': 'django.db.backends.sqlite3',
		'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
	}
}

准备创建数据库:

python manage.py makemigrations toys

结果为:
在这里插入图片描述

  • 将自动生成文件toys/migrations/0001_initial.py

django ORM将根上一步的toys/migrations/0001_initial.py来生成数据表。

执行数据迁移:

python manage.py migrate

结果如下:
在这里插入图片描述

  • 这时才在项目根目录产生一个db.sqlite3数据库文件。

可以到http://www.sqlite.org/download.html下载安装sqlite并点sqlite.exe运行起来。执行命令来查看数据表:

sqlite3 db.sqlite3 ".tables"

输出如下:
在这里插入图片描述
在这里插入图片描述
toys_toy这张表就用于数据的持久化存储了,它是由django的ORM框架生成的,使用如下命令查看建表命令:

sqlite3 db.sqlite3 ".schema toys_toy"

输出:
在这里插入图片描述
关于其他数据表的说明:
在这里插入图片描述
当编写并发送一个CRUD请求到RESTful Web服务后,数据库就会执行类似于下面的操作:

sqlite3 db.sqlite3 "SELECT * FROM toys_toy ORDER BY name;"

4,序列化器

基础工作准备完了,接下来就需要进行Toy实体的序列化反序列化,前提是需要为Toy创建一个序列化器类
具体就是创建rest_framework.serializers.Serializer类的子类,并通过下面两过程进行序列化与反序列化:

  1. 序列化器是模型实例和Python原语之间的中介。
  2. 解析器和渲染器是Python原语与HTTP请求和响应之间的中介。

了解序列化器的工作原理非常重要,因为它是我们将要构建的所有RESTful Web服务的最重要组件之一。

使用上面那个类可能会重复一些在定义模型时使用的内容,但可以进行简化。目前暂时用着再说:

toys/serializers.py:

from rest_framework import serializers
from toys.models import Toy

class ToySerializer(serializers.Serializer):
    pk = serializers.IntegerField(read_only=True)
    name = serializers.CharField(max_length=150)
    description = serializers.CharField(max_length=250)
    release_date = serializers.DateTimeField()
    toy_category = serializers.CharField(max_length=200)
    was_included_in_home = serializers.BooleanField(required=False)
    
    def create(self, validated_data):
        return Toy.objects.create(**validated_data)

    def update(self, instance, validated_data):
        instance.name = validated_data.get('name', instance.name)
        instance.description = validated_data.get('description', instance.description)
        instance.release_date = validated_data.get('release_date', instance.release_date)
        instance.toy_category = validated_data.get('toy_category', instance.toy_category)
        instance.was_included_in_home = validated_data.get('was_included_in_home', instance.was_included_in_home)
        instance.save()
        return instance
  • 属性代表要序列化的字段
  • 必须重写继承自Serializer的create()update()来定义如何创建以及更新一个toy实例
  • create()通过validated_data接受已经验证的数据,创建并返回基于它的实例
  • update()通过instance接受一个已有的实例,通过validated_data接受已经验证的数据,用后者内容更新前者内容,保存并返回新的的实例

5,完成序列化和反序列化

可以通过启动python交互式shell来测试已有的序列化功能:

python manage.py shell

先来导入所需要的stuff:

>>> from datetime import datetime
>>> from django.utils import timezone
>>> from django.utils.six import BytesIO
>>> from rest_framework.renderers import JSONRenderer
>>> from rest_framework.parsers import JSONParser
>>> from toys.models import Toy
>>> from toys.serializers import ToySerializer

创建两个toy实例:

>>> toy_release_date = timezone.make_aware(datetime.now(), timezone.get_current_timezone())
>>> toy1 = Toy(name='Snoopy talking action figure', description='Snoopy speaks five languages', release_d
ate=toy_release_date, toy_category='Action figures', was_included_in_home=False)
>>> toy1.save()
>>> toy2 = Toy(name='Hawaiian Barbie', description='Barbie loves Hawaii', release_date=toy_release_date,
toy_category='Dolls', was_included_in_home=True)
>>> toy2.save()

查看toys_toy表,刚刚保存的两个实例已经存入数据表了:
在这里插入图片描述

接下来就能查看到每个实例的具体属性了:

>>> print(toy1.created)
2020-09-21 17:59:09.346215+00:00
>>> print(toy1.was_included_in_home)
False

序列化——将模型实例转换为 Python 数据类型,并将序列化的数据呈现为JSON格式:

>>> serializer_for_toy2 = ToySerializer(toy2) # 首先实例化序列化器
>>> print(serializer_for_toy2.data)	#通过data属性获取数据
  • 实例化序列化器实现序列化第一步。

输出:
在这里插入图片描述
进一步完成序列化结果渲染:

json_renderer = JSONRenderer()
toy1_rendered_into_json = json_renderer.render(serializer_for_toy1.data) # 然后将序列化结果渲染为JSON格式完成序列化。
toy2_rendered_into_json = json_renderer.render(serializer_for_toy2.data)
print(toy1_rendered_into_json)
print(toy2_rendered_into_json)
  • 将序列化结果渲染为JSON格式完成序列化。

输出:
在这里插入图片描述
反序列化——将呈现为JSON格式的序列化数据解析为易于理解的python字典格式,然后转化为一个模型实例。

解析JSON数据:

json_string_for_new_toy = '{"name":"Clash Royale play set","description":"6 figures from Clash Royale", "release_date":"2017-10-09T12:10:00.776594Z","toy_category":"Playset","was_included_in_home":false}'
json_bytes_for_new_toy = bytes(json_string_for_new_toy, encoding="UTF-8")
stream_for_new_toy = BytesIO(json_bytes_for_new_toy)
parser = JSONParser()
parsed_new_toy = parser.parse(stream_for_new_toy) #首先是解析JSON数据
print(parsed_new_toy)

输出:

{
'name': 'Clash Royale play set',
'description': '6 figures from Clash Royale',
'release_date': '2017-10-09T12:10:00.776594Z',
'toy_category': 'Playset',
'was_included_in_home': False
}

将解析结果转为为django支持的模型数据并保存,完成反序列化:

new_toy_serializer = ToySerializer(data=parsed_new_toy) #然后通过序列化类完成序列化
if new_toy_serializer.is_valid():
	toy3 = new_toy_serializer.save()	#验证无误后存入数据库
	print(toy3.name)

这个序列化和反序列化的过程还是优点复杂,同样放到后面来优化。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之家整理,本文链接:https://www.bmabk.com/index.php/post/98129.html

(0)
小半的头像小半

相关推荐

极客之家——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!