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. 探索SpringBoot中的SpringMVC

    spring boot就是一个大框架里面包含了许许多多的东西,其中spring就是最核心的内容之一,当然就包含spring mvc.spring mvc 是只是spring 处理web层请求的一个模块 ...

  2. 阿里面试题,为什么wait()方法要放在同步块中?

    某天我在***的时候,突然有个小伙伴微信上说:“哥,阿里面试又又挂了,被问到为什么wait()方法要放在同步块中,没答出来!” 我顿时觉得**一紧,仔细回顾一下,如果wait()方法不在同步块中,代码 ...

  3. leetcode 321 Create Max Number

    leetcode 321 Create Max Number greedy的方法,由于有两个数组,我们很自然的想到从数组1中选i个数,数组2中选k-i个数,这样我们只需要遍历max(0, k-数组2长 ...

  4. Java数据结构和算法(七)--AVL树

    在上篇博客中,学习了二分搜索树:Java数据结构和算法(六)--二叉树,但是二分搜索树本身存在一个问题: 如果现在插入的数据为1,2,3,4,5,6,这样有序的数据,或者是逆序 这种情况下的二分搜索树 ...

  5. URI、URL 和 URN的区别

        关于URI:URL类似于住址,它告诉你一种寻找目标的方式.    URL和URN都是URI的子集. URI规范:协议名称://域名.根域名/目录/文件名.后缀#sddf URI :Unifor ...

  6. input输入框的input事件和change事件

    input输入框的onchange事件,要在 input 失去焦点的时候才会触发: 在输入框内容变化的时候不会触发change,当鼠标在其他地方点一下才会触发: onchange 事件也可用于单选框与 ...

  7. redis订阅自动退出

    1.打开报错, error_reporting(E_ALL);ini_set('display_errors', '1'); 2.没有报错,不是php最大执行时间问题,原因是socket超时3.有设置 ...

  8. spring cloud深入学习(四)-----eureka源码解析、ribbon解析、声明式调用feign

    基本概念 1.Registe 一一服务注册当eureka Client向Eureka Server注册时,Eureka Client提供自身的元数据,比如IP地址.端口.运行状况指标的Uri.主页地址 ...

  9. GIT → 05:Git命令行操作

    5.1 打开命令行窗口 安装Git后,在资源管理器的空白处,单击鼠标右键打开窗口,点击 Git Bash Here ,打开Git命令行窗口,在窗口中可直接使用Linux命令操作: 5.2 初始化Git ...

  10. Axure之母版窗口