从小白到高手---api接口和drf(Django Rest_Framework)使用超详解

1.api接口

为了在团队内部形成共识、防止个人习惯差异引起的混乱,我们需要找到一种大家都觉得很好的接口实现规范,而且这种规范能够让后端写的接口,用途一目了然,减少双方之间的合作成本。

目前市面上大部分公司开发人员使用的接口服务架构主要有:restful、rpc。

rpc: 翻译成中文:远程过程调用[远程服务调用].

http://www.lufei.com/api

post请求

action=get_all_student&params=301&sex=1

接口多了,对应函数名和参数就多了,前端在请求api接口时,就会比较难找.容易出现重复的接口

restful: 翻译成中文: 资源状态转换.

把后端所有的数据/文件都看成资源.

那么接口请求数据,本质上来说就是对资源的操作了.

web项目中操作资源,无非就是增删查改.所以要求在地址栏中声明要操作的资源是什么,然后通过http请求动词来说明对资源进行哪一种操作.

POST http://www.lufei.com/api/students/ 添加学生数据

GET http://www.lufei.com/api/students/ 获取所有学生

DELETE http://www.lufei.com/api/students/ 删除1个学生

2.RESTful API规范

1. 域名

应该尽量将API部署在专用域名之下。

https://www.jd.com
https://api.example.com

如果确定API很简单,不会有进一步扩展,可以考虑放在主域名下。

https://example.org/api/

2. 版本(Versioning)

应该将API的版本号放入URL。

http://www.example.com/app/1.0/foo

http://www.example.com/app/1.1/foo

http://www.example.com/app/2.0/foo

另一种做法是,将版本号放在HTTP头信息中,但不如放入URL方便和直观。Github就采用了这种做法。

因为不同的版本,可以理解成同一种资源的不同表现形式,所以应该采用同一个URL。版本号可以在HTTP请求头信息的Accept字段中进行区分(参见Versioning REST Services):

Accept: vnd.example-com.foo+json; version=1.0

Accept: vnd.example-com.foo+json; version=1.1

Accept: vnd.example-com.foo+json; version=2.0

3. 路径(Endpoint)

路径又称"终点"(endpoint),表示API的具体网址,每个网址代表一种资源(resource)

(1) 资源作为网址,只能有名词,不能有动词,而且所用的名词往往与数据库的表名对应。

举例来说,以下是不好的例子:

/getProducts
/listOrders
/retreiveClientByOrder?orderId=1

对于一个简洁结构,你应该始终用名词。 此外,利用的HTTP方法可以分离网址中的资源名称的操作。

GET /products :将返回所有产品清单
POST /products :将产品新建到集合
GET /products/4 :将获取产品 4
PATCH(或)PUT /products/4 :将更新产品 4

(2) API中的名词应该使用复数。无论子资源或者所有资源。

举例来说,获取产品的API可以这样定义

获取单个产品:http://127.0.0.1:8080/AppName/rest/products/1
获取所有产品: http://127.0.0.1:8080/AppName/rest/products

4. HTTP动词

对于资源的具体操作类型,由HTTP动词表示。

常用的HTTP动词有下面四个(括号里是对应的SQL命令)。

  • GET(SELECT):从服务器取出资源(一项或多项)。
  • POST(CREATE):在服务器新建一个资源。
  • PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
  • DELETE(DELETE):从服务器删除资源。

还有三个不常用的HTTP动词。

  • PATCH(UPDATE):在服务器更新(更新)资源(客户端提供改变的属性)。
  • HEAD:获取资源的元数据。
  • OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。

下面是一些例子。

GET /zoos:列出所有动物园
POST /zoos:新建一个动物园(上传文件)
GET /zoos/ID:获取某个指定动物园的信息
PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)
PATCH /zoos/ID:更新某个指定动物园的信息(提供该动物园的部分信息)
DELETE /zoos/ID:删除某个动物园
GET /zoos/ID/animals:列出某个指定动物园的所有动物
DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物

5. 过滤信息(Filtering)

如果记录数量很多,服务器不可能都将它们返回给用户。API应该提供参数,过滤返回结果。

下面是一些常见的参数。query_string 查询字符串,地址栏后面问号后面的数据,格式: name=xx&sss=xxx

?limit=10:指定返回记录的数量
?offset=10:指定返回记录的开始位置。
?page=2&per_page=100:指定第几页,以及每页的记录数。
?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
?animal_type_id=1:指定筛选条件

参数的设计允许存在冗余,即允许API路径和URL参数偶尔有重复。比如,GET /zoos/ID/animals 与 GET /animals?zoo_id=ID 的含义是相同的。

/zoos/2/animals

/animals?zoo_id=2

6. 状态码(Status Codes)

服务器向用户返回的状态码和提示信息,常见的有以下一些(方括号中是该状态码对应的HTTP动词)。

  • 200 OK - [GET]:服务器成功返回用户请求的数据
  • 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 - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。

状态码的完全列表参见这里这里

7. 错误处理(Error handling)

如果状态码是4xx,服务器就应该向用户返回出错信息。一般来说,返回的信息中将error作为键名,出错信息作为键值即可。

{
   
    error: "Invalid API key"
}

8. 返回结果

针对不同操作,服务器向用户返回的结果应该符合以下规范。

  • GET /collections:返回资源对象的列表(数组)
  • GET /collection/ID:返回单个资源对象(json)
  • POST /collection:返回新生成的资源对象(json)
  • PUT /collection/ID:返回完整的资源对象(json)
  • DELETE /collection/ID:返回一个空文档(空字符串)

9. 超媒体(Hypermedia API)

RESTful API最好做到Hypermedia(即返回结果中提供链接,连向其他API方法),使得用户不查文档,也知道下一步应该做什么。

比如,Github的API就是这种设计,访问api.github.com会得到一个所有可用API的网址列表。

{
   
"current_user_url": "https://api.github.com/user",
"authorizations_url": "https://api.github.com/authorizations",
// ...
}

从上面可以看到,如果想获取当前用户的信息,应该去访问api.github.com/user,然后就得到了下面结果。

{
   
  "message": "Requires authentication",
  "documentation_url": "https://developer.github.com/v3"
}

上面代码表示,服务器给出了提示信息,以及文档的网址。

10. 其他

服务器返回的数据格式,应该尽量使用JSON,避免使用XML。

3.Django Rest_Framework简介与安装

3.1 Django Rest_Framework简介

核心思想: 缩减编写api接口的代 – DRF

Django REST framework是一个建立在Django基础之上的Web 应用开发框架,可以快速的开发REST API接口应用。在REST framework中,提供了序列化器Serialzier的定义,可以帮助我们简化序列化与反序列化的过程,不仅如此,还提供丰富的类视图、扩展类、视图集来简化视图的编写工作。REST framework还提供了认证、权限、限流、过滤、分页、接口文档等功能支持。REST framework提供了一个API 的Web可视化界面来方便查看测试接口。

中文文档:https://q1mi.github.io/Django-REST-framework-documentation/#django-rest-framework

github: https://github.com/encode/django-rest-framework/tree/master

英文文档:https://www.django-rest-framework.org/

特点:

提供了定义序列化器Serializer的方法,可以快速根据 Django ORM 或者其它库自动序列化/反序列化;
提供了丰富的类视图、Mixin扩展类,简化视图的编写;
丰富的定制层级:函数视图、类视图、视图集合到自动生成 API,满足各种需要;
多种身份认证和权限认证方式的支持;[jwt]
内置了限流系统;
直观的 API web 界面;
可扩展性,插件丰富

3.2 环境安装与配置

DRF需要以下依赖:

  • Python (2.7, 3.2, 3.3, 3.4, 3.5, 3.6)
  • Django (1.10, 1.11, 2.0)

DRF是以Django扩展应用的方式提供的,所以我们可以直接利用已有的Django环境而无需从新创建。(若没有Django环境,需要先创建环境安装Django)

安装DRF

pip3 install django==2.2
pip3 install djangorestframework

4.drf创建项目流程

4.1 添加rest_framework应用

settings.pyINSTALLED_APPS中添加’rest_framework’。

INSTALLED_APPS = [
    ...
    'rest_framework',
]

接下来就可以使用DRF提供的功能进行api接口开发了。在项目中如果使用rest_framework框架实现API接口,主要有以下三个步骤:

  • 将请求的数据(如JSON格式)转换为模型类对象
  • 操作数据库
  • 将模型类对象转换为响应的数据(如JSON格式)

4.2 创建模型操作类

class Student(models.Model):
    # 模型字段
    name = models.CharField(max_length=100,verbose_name="姓名",help_text='提示文本:不能为空')
    sex = models.BooleanField(default=1,verbose_name="性别")
    age = models.IntegerField(verbose_name="年龄")
    class_null = models.CharField(max_length=5,verbose_name="班级编号")
    description = models.TextField(max_length=1000,verbose_name="个性签名")

    class Meta:
        db_table="tb_student"
        verbose_name = "学生"
        verbose_name_plural = verbose_name

创建数据库

create database students charset utf8;

主引用中__init__.py设置使用pymysql作为数据库驱动

import pymysql
pymysql.install_as_MySQLdb()

settings.py配置文件中设置mysql的账号密码

DATABASES = {
   
    # 'default': {
   
    #     'ENGINE': 'django.db.backends.sqlite3',
    #     'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    # },
    'default': {
   
        'ENGINE': 'django.db.backends.mysql',
        'NAME': "students",
        "HOST": "127.0.0.1",
        "PORT": 3306,
        "USER": "root",
        "PASSWORD":"123456",
    }
}

终端下,执行数据迁移

python manage.py makemigrations
python manage.py migrate

有如下报错:

在这里插入图片描述

解决方案:

注释掉 python/site-packages/django/backends/mysql/base.py中的35和36行代码。

在这里插入图片描述

在这里插入图片描述

解决方案:

backends/mysql/operations.py146行里面新增一个行代码:

query = query.encode()

4.3 创建序列化器

在students应用目录中新建serializers.py用于保存该应用的序列化器。

创建一个StudentModelSerializer用于序列化与反序列化。

from rest_framework.serializers import ModelSerializer
from students.models import Student
# 创建序列化器类,回头会在试图中被调用
class StudentModelSerializer(ModelSerializer):
    class Meta:
        model = Student
        fields = "__all__"
  • model 指明该序列化器处理的数据字段从模型类Student参考生成
  • fields 指明该序列化器包含模型类中的哪些字段,'all’指明包含所有字段

4.4 写视图

在students应用的views.py中创建视图StudentViewSet,这是一个视图集合

from rest_framework.viewsets import ModelViewSet
from .models import Student
from .serializers import StudentModelSerializer
# Create your views here.
class StudentViewSet(ModelViewSet):
    queryset = Student.objects.all() #指明该视图集在查询数据时使用的查询集
    serializer_class = StudentModelSerializer #指明该视图在进行序列化或反序列化时使用的序列化器
  • queryset 指明该视图集在查询数据时使用的查询集
  • serializer_class 指明该视图在进行序列化或反序列化时使用的序列化器

4.5 定义路由

在students应用的urls.py中定义路由信息。

from . import views
from rest_framework.routers import DefaultRouter

# 路由列表
urlpatterns = []

router = DefaultRouter()  # 可以处理视图的路由器,自动通过视图来生成增删改查的url路径
router.register('students', views.StudentViewSet)  #students是生成的url前缀,名称随便写, 向路由器中注册视图集

urlpatterns += router.urls  # 将路由器中的所以路由信息追到到django的路由列表中

最后把students子应用中的路由文件加载到总路由文件中.

from django.contrib import admin
from django.urls import path,include  #path:直接写路径,re_path:可以写正则匹配

urlpatterns = [
    path('admin/', admin.site.urls),
    path("stu/",include("students.urls")),
]

4.6 运行测试

运行该django项目

在浏览器输入路径,可以看到DRF提供的API Web浏览页面

在页面底部可以提交post请求,添加到数据库

在网址中输入路径/1,可以访问id为1的信息

在网址中输入路径/S/,可以访问删除的接口

在这里插入图片描述

5. 序列化器–Serializer

作用:

1. 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串
2. 反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
3. 反序列化,完成数据校验功能

定义好Serializer类后,就可以创建Serializer对象了。

5.1 Serializer的构造方法

Serializer(instance=None, data=empty, **kwarg)

说明:

1)用于序列化时,将模型类对象传入instance参数

2)用于反序列化时,将要被反序列化的数据传入data参数

3)除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据,如

serializer = AccountSerializer(account, context={
   'request': request})

通过context参数附加的数据,可以通过Serializer对象的context属性获取。

  1. 使用序列化器的时候一定要注意,序列化器声明了以后,不会自动执行,需要我们在视图中进行调用才可以。
  2. 序列化器无法直接接收数据,需要我们在视图中创建序列化器对象时把使用的数据传递过来。
  3. 序列化器的字段声明类似于我们前面使用过的表单系统。
  4. 开发restful api时,序列化器会帮我们把模型数据转换成字典.
  5. drf提供的视图会帮我们把字典转换成json,或者把客户端发送过来的数据转换字典.

5.2 序列化功能的使用

1 定义一个序列化器,在应用中创建一个py文件,serializers.py

from rest_framework import serializers
class StudentSerizlizer(serializers.Serializer):
    name = serializers.CharField()
    age = serializers.IntegerField()
    class_null = serializers.CharField()
    description = serializers.CharField()

2 写views.py文件

from django.shortcuts import render
from django.http import JsonResponse
from django.views import View
from app01 import models
from .serializers import StudentSerizlizer
# Create your views here.
class StudentView(View):
    def get(self,request):
        one = models.Student.objects.get(id=1)
        serializer = StudentSerizlizer(instance=one)
        print(serializer.data)  #结果为:{'name': 'ceshi1', 'age': 6, 'class_null': '1', 'description': '90886'}
        # all = models.Student.objects.all()
        # serializer = StudentSerizlizer(instance=all,many=True) #结果为:[{},{}]形式
        #many=True 在序列化的数据是多条时,需要加上many=True
        #print(serializer.data)
        #结果为:[OrderedDict([('name', 'ceshi1'), ('age', 6), ('class_null', '1'), ('description', '90886.....
        return JsonResponse(serializer.data,safe=False,json_dumps_params={
   'ensure_ascii':False})
    	# JsonResponse回复的就是Json类型数据,JsonResponse响应非字典类型数据时,需要加上safe=False这个参数才行,json_dumps_params在浏览器中显示中文

3 配置路由

from django.urls import path
from use_serializers import views
urlpatterns = [
    path('students/', views.StudentView.as_view())
]
from django.contrib import admin
from django.urls import path, include #path:直接写路径,re_path:可以写正则匹配

urlpatterns = [
    path('admin/', admin.site.urls),
    path('app01/', include('app01.urls')),
    path('use01/', include('use_serializers.urls')),
]

测试结果:

在这里插入图片描述

5.3 反序列化功能的使用

5.3.1 一个简单的实例

1 定义一个序列化器,在当前应用中新建serializers.py

from rest_framework import serializers
class StudentSerializers(serializers.Serializer):
    name = serializers.CharField(max_length=4) #校验长度是否是4
    age = serializers.IntegerField(max_value=18) #校验长度是否是18
    class_null = serializers.CharField()
    description = serializers.CharField(allow_blank=True) #允许该字段不填,allow_null用null来存空值

2 写views.py文件

from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
from django.views import View
from .serializers import StudentSerializers
# Create your views here.
class StuView(View):
    def post(self,request):
        data  = {
   
            'name':request.POST.get('name'),
            'age' : request.POST.get('age'),
            'class_null':request.POST.get('class_null'),
            'description':request.POST.get('description'),
        }
        ser = StudentSerializers(data=data)
        if ser.is_valid():  #校验通过为True
            print(ser.validated_data) #校验通过的正确信息
        print(ser.errors) #校验未通过的错误信息
        return HttpResponse('ok')

3 url:

from django.urls import path
from use_unserializers import views
urlpatterns = [
    path('students/',views.StuView.as_view())
]
5.3.2 全局钩子和局部钩子

1 定义一个序列化器,在当前应用中新建serializers.py

from rest_framework import serializers

def check01(val):
    if '666' in val :
        raise serializers.ValidationError('错误!')
    else:
        return val
class StudentSerializers(serializers.Serializer):
    name = serializers.CharField(max_length=4,validators=[check01,])
    age = serializers.IntegerField(max_value=18)
    class_null = serializers.IntegerField()
    description = serializers.CharField(allow_blank=True)
    #局部钩子 validate_字段名:针对单个字段进行校验
    def validate_name(self,val):
        if '777' in val :
            raise serializers.ValidationError('错误!!')
        return val
    #全局钩子 validate : 针对多个属性数据进行校验
    def validate(self, data):
        print(data)
        age = data.get('age')
        print(age)
        class_null = data.get('class_null')
        print(class_null)
        if age == class_null:
            raise serializers.ValidationError('错误!!!!')
        return data

执行顺序:

# is_valid()方法时,先校验序列化器类中的所有属性Field(CharField(参数))参数对应的校验规则
# 再执行局部钩子
# 举例:比如有name和age两个属性,先执行name 的参数校验,在执行name的局部钩子(validate_name(self,val)),然后再执行age属性的参数校验,再执行age的局部钩子,最后所有属性的参数校验和局部钩子校验完成之后,执行全局钩子

# 最后执行全局钩子

2 views.py文件

from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
from django.views import View
from .serializers import StudentSerializers
from app01 import models
# Create your views here.
class StuView(View):
    def post(self,request):
        data  = {
   
            'name':request.POST.get
  • 17
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
DRF (Django REST framework) is a powerful framework for building Web APIs in Django. Serializer classes in DRF are used to convert complex data types, such as Django model instances, into Python data types that can be easily rendered into JSON/XML responses or parsed from request data. The `serializer_class` attribute is used in DRF's view classes (e.g., `APIView` or one of its subclasses) to specify the serializer class that should be used for the request/response data serialization. It tells DRF how to serialize and deserialize the data exchanged between the client and the server. For example, consider the following code snippet: ```python from rest_framework.views import APIView from rest_framework.serializers import Serializer class MyView(APIView): serializer_class = MySerializer # Specify the serializer class def get(self, request): queryset = MyModel.objects.all() serialized_data = self.serializer_class(queryset, many=True).data return Response(serialized_data) ``` In this example, `MySerializer` is the serializer class defined by you that determines how the `MyModel` instances should be serialized. The `serializer_class` attribute is set to `MySerializer`, indicating that this serializer should be used for data serialization in this view. By specifying the `serializer_class`, DRF handles the serialization and deserialization of data automatically based on the serializer's configuration. It helps simplify the API development process by handling most of the boilerplate code involved in data conversions.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值