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. 取消 ios 上下滑动

  2. WPF 禁用中文

    <TextBox InputMethod.IsInputMethodEnabled="False" />

  3. 在scrapy中利用Selector来提取数据

    1.创建对象 Selector类的实现位于scrapy.selector模块,创建Selector对象的时候,可以将页面的Html文档字符串传递给Selector构造器方法 2.选中数据 调用Sele ...

  4. Django之ORM多表操作

    1.创建一对多: 1.外键建在多的一方(如:一个出版社可出版多本书,所以建在书的表) 2.创建表: 1.创建外键 2.关联的表名 2.一对多数据的操作 2.1数据的添加: 第一种方法: 第二种方法: ...

  5. UVa-401 Palindromes回文词

    虽然是水题,但是容易错.参照了紫书的代码可以写的很简洁.主要还是注意常量数组的使用,能让代码变得简单许多 #include <iostream> #include <cstdio&g ...

  6. Leetcode138. Copy List with Random Pointer复制带随机指针的链表

    给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点. 要求返回这个链表的深度拷贝. 方法一: class Solution { public: RandomLis ...

  7. MySQL系列(五)--二进制日志对主从复制的影响

    MySQL复制是基于主库上的二进制日志来完成,复制是异步的,可能存在延迟 MySQL日志分为: 1.服务层日志:二进制日志.通用日志.慢查日志 2.存储引擎层日志:innodb中重做日志和回滚日志 二 ...

  8. Spring这棵大树

    目前项目中用的框架大多数都是Spring,一直想找时间对这个框架做一个全面的了解. 今天先以导图的形式画出来Spring都包含的主要模块,即使有些模块目前用不上,但说不定在将来的应用场景时想到Spri ...

  9. 你需要一个新的model实体的时候必须new一个.奇怪的问题: 使用poi解析Excel的把数据插入数据库同时把数据放在一个list中,返回到页面展示,结果页面把最后一条数据显示了N次

    数据库显示数据正常被插 插入一条打印一次数据,也是正常的,但是执行完,list就全部变成了最后一条数据.很奇怪 单步调试 给list插入第一条数据 model是6607 连续插了多条数据都是6607 ...

  10. NoSQL最新现状和趋势:云NoSQL数据库将成重要增长引擎

    NoSQL最早起源于1998年,但从2009年开始,NoSQL真正开始逐渐兴起和发展.回望历史应该说NoSQL数据库的兴起,完全是十年来伴随互联网技术,大数据数据的兴起和发展,NoSQL在面临大数据场 ...