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. Activiti实战03_Hello World

    Hello World如此经典,以至于几乎学习没一门新的技术都是从Hello World开始,可能意味着开启了新世界的大门吧,接下来就让我们一起步入到Activiti的世界中吧! 本文所使用开发环境 ...

  2. 关于mybatis-config.xml文件的基础解释

    今天是我第一天落户博客园,想一想从mybatis框架开始写起吧.mybatis框架与Hibernate框架相比来说,专注于SQL语句,对SQL语句的要求比较高吧. 我觉得,对于mybatis框架来说, ...

  3. IO流12 --- 转换流InputStreamReader --- 技术搬运工(尚硅谷)

    InputStreamReader 将字节输入流转换为字符输入流 @Test public void test1(){ InputStreamReader isr = null; try { //字节 ...

  4. Linux驱动手动绑定和解绑定方法

    linux内核从2.6.13-rc3开始,提供了在用户空间,可动态的绑定和解绑定设备和设备驱动之间关系的功能.在这之前,只能通过insmod(modprobe)和rmmod来绑定和解绑,而且这种绑定和 ...

  5. PHP jpgraph的一点小提示和方法

    PHP默认是不启用GD库的,因为需要在php.ini的配置文件中将extension=php_gd2.dll注释打开.打开后你就可以画一些你想画的各种奇葩图案了.什么?不会画?那回去学基础! 今天看了 ...

  6. Layui 获取表单提交数据

    HTML<div class="layui-card-header layuiadmin-card-header-auto"> <form class=" ...

  7. springcloud熔断器代码简单实现

    Feign包赖熔断器相关的包,所有不用再单独引用 1.在服务消费方的基础上修改,开启熔断机制, feign.hystrix.enabled=true 2.修改消费者调用的接口 package com. ...

  8. 【html、CSS、javascript-9】jquery-选择器及过滤器

    一.选择器与过滤器 选择器 实例 选取 * $("*") 所有元素 #id $("#lastname") id="lastname" 的元素 ...

  9. webpack4配置react开发环境

    webpack4大大提高了开发效率,简化了配置复杂度,作为一个大的版本更新,作为一个对开发效率执着的爱折腾的程序员,已经忍不住要尝尝鲜了 首先是cli和webpack的分离,开发webpack应用程序 ...

  10. JS---案例:大量字符串拼接效果实现

    案例:大量字符串拼接效果实现 按钮点击,字符串拼接,最后效果字符串,str input有很多,type来分就有button和text,需要找出inputs[i].value是text的 所以用!=&q ...