1.RESTful

1.1 定义

REST(Representational State Transfer)与技术无关,代表一种软件架构风格,中文为表征状态转移。

1.2 RESTful API设计

  • API与用户的通信协议,总是使用HTTPS协议

  • 域名

  • 版本

  • 路径,网络上的任何东西都是资源,均使用名词表示(可复数)

  • method

    • GET :从服务器取出资源(一项或多项)
    • POST:在服务器新建一个资源
    • PUT:在服务器更新资源(客户端提供改变后的完整资源)
    • PATCH:在服务器更新资源(客户端提供改变属性)
    • DELETE:从服务器删除资源
  • 过滤,通过在url上传递参数的形式传递过滤条件

  • 状态码

    常见状态码:

    200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
    201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
    202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
    204 NO CONTENT - [DELETE]:用户删除数据成功。
    400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
    401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
    403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
    404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
    406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
    410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
    422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
    500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
  • 错误信息,状态码是4xx时,应该返回错误信息,error当做key

    {
    error:"Invalid API key"
    }
  • 返回结果,针对不同操作,服务器向用户返回的结果应该符合以下规范

    GET /collection:返回资源对象的列表(数组)
    GET /collection/resource:返回单个资源对象
    POST /collection:返回新生成的资源对象
    PUT /collection/resource:返回完整的资源对象
    PATCH /collection/resource:返回完整的资源对象
    DELETE /collection/resource:返回一个空文档
  • 返回url

例如访问一个接口来获取员工信息,而我们需要的数据中由员工所属部门信息。

需要跨表查询,这时restful建议部门信息返回一个url,然后用户再向该接口发送请求拿到部门信息


## 2.Django Rest Framework 框架 Django Rest Framework帮助我们快速构建符合RESTful的数据。通常用于前后端分离项目之间的数据资源传输。 ### 2.1 Serializer的简单使用 serializers序列化器,帮助我们快速序列化在数据库中查询到的数据。 下面通过一个小例子来简单看一下Serializer的使用 表结构model.py ```python
from django.db import models # Create your models here.
class Publisher(models.Model):
name = models.CharField(max_length=32) class Author(models.Model):
name = models.CharField(max_length=32, ) class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=6, decimal_places=2)
pub_date = models.DateTimeField()
pub = models.ForeignKey('Publisher', on_delete=models.CASCADE)
authors = models.ManyToManyField('Author')

路由urls.py

from django.conf.urls import url
from app01 import views urlpatterns = [
url(r'^books/', views.BookListView.as_view()),
]

2.1.1 通过json模块手动序列化

views.py文件

from django.shortcuts import render, HttpResponse
from django.views import View
import json #使用json模块序列化,时间类型需要单独转成字符串再序列化
class BookListView(View):
def get(self, request, *args, **kwargs):
obj_list = models.Book.objects.all().values('title', 'pub', 'pub_date')
return HttpResponse(json.dumps(list(obj_list), ensure_ascii=False)) # pub_date为日期类型无法json序列化

通过json手动序列化,当数据中有时间类型时,序要单独处理成字符串类型,才能进行序列化。

2.1.2 通过django的JsonResponse

views.py文件

from django.http.response import JsonResponse

#使用JsonResponse对象序列化,可以直接处理时间类型
class BookListView(View):
def get(self, request, *args, **kwargs):
obj_list = models.Book.objects.all().values('title', 'pub', 'pub_date')
return JsonResponse(list(obj_list), safe=False, json_dumps_params={
'ensure_ascii': False}) # safe参数为False:当最外层不为字典时也可序列化,json_dumps_params参数:设置json序列化的参数

JsonResponse类不能对查询到的query_set对象直接序列化,对外键等字段关联对象数据不好处理。

2.1.3 使用django自带的序列化器

views.py文件

#使用django自带的序列化器
from django.core import serializers
class BookListView(View): def get(self, request, *args, **kwargs):
""" 获取所有的数据 返回所有的书籍数据 json格式"""
# 1. 从数据库获取所有数据
all_books = models.Book.objects.all() data = serializers.serialize('json', all_books)
return HttpResponse(data)

序列化后的数据格式

[
{
"model": "app01.book",
"pk": 1,
"fields": {
"title": "\u4e5d\u9634\u771f\u7ecf",
"price": "9.99",
"pub_date": "2019-06-04T07:15:56Z",
"pub": 1,
"authors": [
1,2
]
}
},
{
"model": "app01.book",
"pk": 2,
"fields": {
"title": "\u4e5d\u9633\u771f\u7ecf",
"price": "98.30",
"pub_date": "2019-04-16T07:16:39Z",
"pub": 1,
"authors": [
1
]
}
},
{
"model": "app01.book",
"pk": 3,
"fields": {
"title": "\u8475\u82b1\u5b9d\u5178",
"price": "65.50",
"pub_date": "2019-07-25T07:17:09Z",
"pub": 2,
"authors": [
2
]
}
}
]

2.1.4 使用Rest Framework的Response对象

views.py文件

#使用RestFramework 的response对象
from rest_framework.views import APIView
from rest_framework.response import Response class BookListView(APIView):
def get(self, request, *args, **kwargs):
all_books = models.Book.objects.all().values('title', 'authors__name','pub_date')
print(all_books)
return Response(all_books)

数据格式

[
{
"title": "九阴真经",
"authors__name": "沙和尚",
"pub_date": "2019-06-04T07:15:56Z"
},
{
"title": "九阴真经",
"authors__name": "猪悟能",
"pub_date": "2019-06-04T07:15:56Z"
},
{
"title": "九阳真经",
"authors__name": "沙和尚",
"pub_date": "2019-04-16T07:16:39Z"
},
{
"title": "葵花宝典",
"authors__name": "猪悟能",
"pub_date": "2019-07-25T07:17:09Z"
}
]

2.1.5 使用Rest Framework的序列化器

首先要创建一个序列化器

serializer.py文件

from rest_framework import serializers

class AuthorSerializer(serializers.Serializer): #Author表的序列化器
name = serializers.CharField() class PublisherSerializer(serializers.Serializer): #Publisher表的序列化器
name = serializers.CharField() class BookSerializer(serializers.Serializer): #Book表的序列化器
title = serializers.CharField() #普通字段类型和数据库类型相同即可,字段名也要相同
price = serializers.DecimalField(max_digits=6,decimal_places=2)
pub_date = serializers.DateTimeField()
pub = PublisherSerializer() #外键使用,使用定义的序列化器实例化
authors = serializers.SerializerMethodField() #多对多字段,定义get_字段名方法 def get_authors(self,obj): #obj当前表的对象
data_obj = AuthorSerializer(obj.authors.all(),many=True) #多条数据要设置many为True
return data_obj.data #返回对象的data

views.py文件

class BookListView(APIView):
def get(self, request, *args, **kwargs):
all_books = models.Book.objects.all()
ser_obj = BookSerializer(all_books, many=True)#多条数据要设置many为True return Response(ser_obj.data)#返回对象的data

数据格式:

[
{
"title": "九阴真经",
"price": "9.99",
"pub_date": "2019-06-04T07:15:56Z",
"pub": {
"name": "沙和尚出版社"
},
"authors": [
{
"name": "沙和尚"
},
{
"name": "猪悟能"
}
]
},
{
"title": "九阳真经",
"price": "98.30",
"pub_date": "2019-04-16T07:16:39Z",
"pub": {
"name": "沙和尚出版社"
},
"authors": [
{
"name": "沙和尚"
}
]
},
{
"title": "葵花宝典",
"price": "65.50",
"pub_date": "2019-07-25T07:17:09Z",
"pub": {
"name": "二师兄出版社"
},
"authors": [
{
"name": "猪悟能"
}
]
}
]

2.2 使用Serializer实现简单的增删改

urls.py文件

from django.conf.urls import url
from app01 import views urlpatterns = [
url(r'^books/', views.BookListView.as_view()), #获取多条数据和添加数据
url(r'^book/(\d+)/', views.BookView.as_view()), #获取单条数据,编辑和删除数据
]

2.2.1 获取多条数据和添加数据

serializer.py文件

from rest_framework import serializers
from app01 import models class AuthorSerializer(serializers.Serializer):
id = serializers.IntegerField()
name = serializers.CharField() class PublisherSerializer(serializers.Serializer):
name = serializers.CharField() class BookSerializer(serializers.Serializer):
title = serializers.CharField()
price = serializers.DecimalField(max_digits=6, decimal_places=2)
pub_date = serializers.DateTimeField()
pub = PublisherSerializer(read_only=True) #GET请求时需要的数据设置为只读,POST时可为空
authors = serializers.SerializerMethodField(read_only=True)
post_pub = serializers.IntegerField(write_only=True) #POST和PUT时的数据只写,GET时可为空
post_authors = serializers.ListField(write_only=True) def get_authors(self, obj):
data_obj = AuthorSerializer(obj.authors.all(), many=True) #多个对象需要many为True
return data_obj.data def create(self, validated_data): #create方法用于添加数据,validated_data校验完的数据
book_obj = models.Book.objects.create(
title=validated_data.get('title'),
price=validated_data.get('price'),
pub_date=validated_data.get('pub_date'),
pub_id=validated_data.get('post_pub'),
)
book_obj.authors.set(validated_data.get('post_authors'))
return book_obj # 将book对象返回

view.py文件

from app01.serializer import BookSerializer
class BookListView(APIView):
def get(self, request, *args, **kwargs):
all_books = models.Book.objects.all()
obj = BookSerializer(all_books,many=True)
return Response(obj.data) def post(self,request,*args,**kwargs):
print(request.data)
obj = BookSerializer(data=request.data)
if obj.is_valid(): #对数据进行校验,貌似序列化器里的多对多不会校验
obj.save() #会去序列化器里找create()方法
return Response(obj.data) #校验成功返回添加的数据
return Response({'error': obj.errors}) #校验失败返回错误信息

POST的数据

{
"title": "葵花宝典续集",
"price": "65.50",
"pub_date": "2019-07-25T07:17:09Z",
"post_pub": 1,
"post_authors": [
1
]
}

返回的数据

{
"title": "葵花宝典续集",
"price": "65.50",
"pub_date": "2019-07-25T07:17:09Z",
"pub": {
"name": "沙和尚出版社"
},
"authors": [
{
"id": 1,
"name": "沙和尚"
}
]
}

2.2.2 获取单条数据、编辑和修改

serializer.py文件

class BookSerializer(serializers.Serializer):
title = serializers.CharField()
price = serializers.DecimalField(max_digits=6, decimal_places=2)
pub_date = serializers.DateTimeField()
pub = PublisherSerializer(read_only=True)
authors = serializers.SerializerMethodField(read_only=True)
post_pub = serializers.IntegerField(write_only=True)
post_authors = serializers.ListField(write_only=True) def get_authors(self, obj):
data_obj = AuthorSerializer(obj.authors.all(), many=True)
return data_obj.data def create(self, validated_data): # validated_data校验完的数据
book_obj = models.Book.objects.create(
title=validated_data.get('title'),
price=validated_data.get('price'),
pub_date=validated_data.get('pub_date'),
pub_id=validated_data.get('post_pub'),
)
book_obj.authors.set(validated_data.get('post_authors'))
return book_obj # 将book对象返回 def update(self, instance, validated_data): # 修改数据时调用update方法,instance当前要求改的数据对象
instance.title = validated_data.get('title', instance.title)
instance.price = validated_data.get('price', instance.price)
instance.pub_date = validated_data.get('pub_date', instance.pub_date)
instance.pub_id = validated_data.get('post_pub', instance.pub_id)
instance.save()
instance.authors.set(validated_data.get('post_authors',instance.authors.all()))
return instance #返回修改后的数据对象

view.py文件

class BookView(APIView):
def get(self, request,pk, *args, **kwargs):
book = models.Book.objects.filter(pk=pk).first()
obj = BookSerializer(book)
return Response(obj.data) def put(self,request,pk,*args,**kwargs): #修改资源
book = models.Book.objects.filter(pk=pk).first()
obj = BookSerializer(data=request.data,instance=book,partial=True) #partial为True表示可以只传修改的那部分值
if obj.is_valid():
obj.save() #保存时会调用序列化器定义好的update()方法
return Response(obj.data) #校验成功返回修改后的对象
return Response(obj.errors) def delete(self,request,pk,*args,**kwargs): #删除资源
book = models.Book.objects.filter(pk=pk).first()
if book:
book.delete()
return Response({'info':'删除成功'})
return Response({'info': '数据不存在'})

PUT的数据

{
"title": "葵花宝典1",
"price": "63.50",
"pub_date": "2019-07-25T07:17:09Z",
"post_pub": 1,
"post_authors": [
1
]
} #也可只穿修改的值
{
"title": "葵花宝典1" #注:只有一个元素,不要加逗号,不然校验不通过
}

返回的数据

{
"title": "葵花宝典1",
"price": "63.50",
"pub_date": "2019-07-25T07:17:09Z",
"pub": {
"name": "沙和尚出版社"
},
"authors": [
{
"id": 1,
"name": "沙和尚"
}
]
}

2.3 Serializer的校验

除了在定义序列化器根据定义的字段类型进行校验外,我们还可以自定义校验

2.3.1 自定义校验器

serializer.py文件

def my_validator(value): #value为要校验的值
if '大' in value:
raise serializers.ValidationError('标题包含敏感字符') #校验不通过抛出异常
return value #校验通过返回当前值 class BookSerializer(serializers.Serializer):
title = serializers.CharField(validators=[my_validator]) #自定义校验器my_validator对title字段进行校验
price = serializers.DecimalField(max_digits=6, decimal_places=2)
pub_date = serializers.DateTimeField()
pub = PublisherSerializer(read_only=True)
authors = serializers.SerializerMethodField(read_only=True)
post_pub = serializers.IntegerField(write_only=True)
post_authors = serializers.ListField(write_only=True)

发送的数据

{
"title": "大小",
"price": "99.30",
"pub_date": "2019-04-16T07:16:39Z",
"post_pub": 1,
"post_authors": [
1
]
}

返回的数据

{
"error": {
"title": [
"标题包含敏感字符"
]
}
}

2.3.2 局部钩子函数

局部钩子函数写在序列化器类内部,可以对字段进行校验。

serializer.py文件

class BookSerializer(serializers.Serializer):
title = serializers.CharField()
price = serializers.DecimalField(max_digits=6, decimal_places=2)
pub_date = serializers.DateTimeField()
pub = PublisherSerializer(read_only=True)
authors = serializers.SerializerMethodField(read_only=True)
post_pub = serializers.IntegerField(write_only=True)
post_authors = serializers.ListField(write_only=True) def validate_title(self, value): #局部钩子 validate_字段名
if '大' in value:
raise serializers.ValidationError('标题包含敏感字符')
return value

发送数据和接收数据同自定义校验器。

2.3.3 全局钩子函数

全局钩子可以对所有字段进行校验。

serializer.py文件

class BookSerializer(serializers.Serializer):
title = serializers.CharField()
price = serializers.DecimalField(max_digits=6, decimal_places=2)
pub_date = serializers.DateTimeField()
pub = PublisherSerializer(read_only=True)
authors = serializers.SerializerMethodField(read_only=True)
post_pub = serializers.IntegerField(write_only=True)
post_authors = serializers.ListField(write_only=True) def validate(self, attrs):
if '大' in attrs['title']: #attr包含所有数据{'title': '大小', 'price': '99.30', 'pub_date': '2019-04-16T07:16:39Z', 'post_pub': 1, 'post_authors': [1]}
raise serializers.ValidationError('标题包含敏感字符')
return attrs #校验通过返回所有数据

发送数据和接收数据同自定义校验器。

2.4 ModelSerializer的简单使用

ModelSerializer序列化器,使用起来比Serializer更加方便,它直接和Django的ORM的model表关联了起来。对数据库的数据的序列化更加方便。

serializer.py文件

class BookSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book #关联的model
fields = '__all__' #所有的字段

GET到的数据

[
{
"id": 2,
"title": "九阳真经续集",
"price": "93.30",
"pub_date": "2019-04-16T07:16:39Z",
"pub": 1,
"authors": [
1
]
},
{
"id": 3,
"title": "葵花宝典",
"price": "65.50",
"pub_date": "2019-07-25T07:17:09Z",
"pub": 2,
"authors": [
2
]
}
]

这时外键和多对多等字段请求的只是id,下面一种简单的解决方式

serializer.py文件

class BookSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = '__all__'
depth = 1 #深度为1

GET到的数据

[
{
"id": 2,
"title": "九阳真经续集",
"price": "93.30",
"pub_date": "2019-04-16T07:16:39Z",
"pub": {
"id": 1,
"name": "沙和尚出版社"
},
"authors": [
{
"id": 1,
"name": "沙和尚"
}
]
},
{
"id": 3,
"title": "葵花宝典",
"price": "65.50",
"pub_date": "2019-07-25T07:17:09Z",
"pub": {
"id": 2,
"name": "二师兄出版社"
},
"authors": [
{
"id": 2,
"name": "猪悟能"
}
]
}
]

但是这种方式在提交的时候变得不方便,所以一般通过下列方式来获取外键的详细数据

serializer.py文件

class BookSerializer(serializers.ModelSerializer):
pub_info = serializers.SerializerMethodField(read_only=True) #GET时需要该字段
authors_info = serializers.SerializerMethodField(read_only=True) def get_pub_info(self,obj):
return PublisherSerializer(obj.pub).data def get_authors_info(self,obj):
return AuthorSerializer(obj.authors.all(),many=True).data class Meta:
model = models.Book
fields = '__all__'
extra_kwargs = { #额外的设置
'pub':{'write_only':True}, #设置字段的属性,POST和PUT时需要该字段
'authors':{'write_only':True},
}

Django Rest Framework Serializer的简单使用的更多相关文章

  1. Django REST framework serializer 嵌套显示绝对路径

    在 Django REST framework官方文档提到,当调用Serializer时,应当传入request参数,以便生成完整的url而不是相对url.使用ModelSerializer时requ ...

  2. Django REST framework的使用简单介绍

    官方文档:https://www.django-rest-framework.org/ GitHub源码:https://github.com/encode/django-rest-framework ...

  3. django rest framework serializer中获取request中user方法

    views.py   serializer = self.get_serializer(data=request.data, context={'request': request}) seriali ...

  4. Django REST Framework API Guide 06

    本节大纲 1.Validators 2.Authentication Validators 在REST框架中处理验证的大多数时间,您将仅仅依赖于缺省字段验证,或在序列化器或字段类上编写显式验证方法.但 ...

  5. Sentry 开发者贡献指南 - Django Rest Framework(Serializers)

    Serializer 用于获取复杂的 python 模型并将它们转换为 json.序列化程序还可用于在验证传入数据后将 json 反序列化回 Python 模型. 在 Sentry,我们有两种不同类型 ...

  6. Django REST framework 单元测试

    Django REST framework 单元测试 只是简单记录一下测试代码怎么写 环境 Win10 Python3.7 Django2.2 项目 参照官网 快速开始 写了一个 demo 测试 参照 ...

  7. Django REST Framework简单入门(一)

    Django REST Framework(简称DRF),是一个用于构建Web API的强大且灵活的工具包. REST这个词,是Roy Thomas Fielding在他2000年的博士论文中提出的. ...

  8. Django REST Framework(一) Serializer和ModelSerializer

    REST Framework概述 Django REST framework是一套基于Django的REST框架,是一个用于构建Web API的功能强大且灵活的工具包. 1.RESTful 简述Rep ...

  9. Django Rest framework基础使用之 serializer

    rest-framework文档地址:http://www.django-rest-framework.org/ Django Rest framework是一个非常强大且灵活的工具包,用于构建web ...

随机推荐

  1. RxJS 入门指引和初步应用

    作者:徐飞链接:https://zhuanlan.zhihu.com/p/25383159来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. RxJS是一个强大的React ...

  2. PAT甲级——A1053 Path of Equal Weight

    Given a non-empty tree with root R, and with weight W​i​​ assigned to each tree node T​i​​. The weig ...

  3. oracle创建新的连接(表空间?数据库?)

    一.创建用户名密码 create user username identified by password    --username 是用户名:password 是密码 二.给用户附权.撤权 gra ...

  4. gulp入门之常见处理方式(三)

    整合 streams 来处理错误 默认情况下,在 stream 中发生一个错误的话,它会被直接抛出,除非已经有一个时间监听器监听着 error时间. 这在处理一个比较长的管道操作的时候会显得比较棘手. ...

  5. 二、Web Service开发(.net)

    .net平台内建了对Web Service的支持,包括Web Service的构建和使用.与其它开发平台不同,使用.net平台,你不需要其他的工具或者SDK就可以完成Web Service的开发了.. ...

  6. xshell下载免费版

    正在使用的xshell 5不能使用,提示xshell 5评估期已过,重新安装还是不行.其实xshell 5有免费版的,即Home & school 版本.卸载原程序,下载安装免费版本的xshe ...

  7. pytorch 加载训练好的模型做inference

    前提: 模型参数和结构是分别保存的 1. 构建模型(# load model graph) model = MODEL() 2.加载模型参数(# load model state_dict) mode ...

  8. CSS实例 display display 边距

    CSS学习大纲 在标签上设置style属性: background-color:#2459a2 ; height:48px ; 编写CSS样式: 1.标签的style属性 2.写在head里面,sty ...

  9. 使用requireJs进行模块化开发

    requireJs使用 requireJs 使用require.js的第一步,是先去官方网站下载最新版本. 下载后,假定把它放在js子目录下面,就可以加载了. <script src=" ...

  10. HTML 语法简要总结

    HTML基本语法 认识网页 网页主要由文字.图像和超链接等元素构成.当然,除了这些元素,网页中还可以包含音频.视频以及Flash等. 常见浏览器内核介绍 浏览器是网页运行的平台,常用的浏览器有IE.火 ...