热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

restful规范与drf的安装使用&drf中APIView源码分析

内容概要web开发模式API接口postman测试软件的使用restful规范drf的安装与使用cbv的View源码分析APIView源码分析

restful 规范与 drf 的安装使用 & drf 中 APIView 源码分析

内容概要
  • web 开发模式
  • API 接口
  • postman 测试软件的使用
  • restful 规范
  • drf 的安装与使用
  • cbv 的 View 源码分析
  • APIView 源码分析
  • drf 的 Request 类
  • drf 的 APIView 类执行过程

内容详细

web 开发模式

1、前后端不分离

在开发一个网站的过程中,前端页面需要使用后端框架的模板语法(DTL) 来渲染,比如 Django 自带的模板语法或者 jinjia2,这种前端页面在后端渲染完成之后才会把页面文档传送给前端

image

2、前后端分离

目前主流的开发模式,这种模式中前端先在后端的静态文件服务器(nfs)中获取静态文件(static 中的HTML、CSS、JS代码),需要数据的时候向后端发送请求只获取json格式的数据,再在前端运用js的BOM与DOM操作对页面进行渲染。

这样便实现了前后端分离,前端只需要从后端获取一定格式的数据,那么前端就可以是一个网页、app或者小程序,提高开发水平。

image

API 接口

简介: api 接口是前后端交互数据的媒介

api 接口包含:

  • 1、url 地址: 向后端请求数据的地址
    • https://api.example.com
  • 2、请求方式 : get、post、put、patch、delete
  • 3、请求参数:在 url 地址后面紧跟着的 ?name="elijah",可以看作是过滤条件
    • https://api.example.com/v1/zoos?limit=10
  • 4、响应结果:包括响应首行(响应状态码)、响应头、响应体(json格式数据)

postman 测试软件的使用

过去我们开发网站开放出来的接口一般使用浏览器发送get请求来进行测试,但基于api接口的restful设计规范,我们还需要使用 post请求、put请求等,而浏览器只能发送 get请求

postman 是一种测试接口共组,在 postman 中可以满足我们的测试需求

市面上也有许多测试软件(postwoman),我们使用主流的postman

下载地址https://www.getpostman.com/downloads/

使用:

1、发送请求

image

前后端数据交互的编码格式:

  • urlencoded:正常的post请求提交数据:name=elijah
  • formdata:post请求上传文件:带文件二进制形式
  • json:在body体中的数据格式为:{"name":"elijah","age":18} (用的多)

发起请求时,可以在 body 中书写请求体:

image

image

2、建立集合批量发起测试

image

image

image

同时,这个批量测试也支持导出文件,然后发送给别人,再从文件中导出

image

restful 规范

REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”或“表现层状态转化”。它首次出现在2000年Roy Fielding的博士论文中。

在前后端分离的开发模式中,为了方便数据交互,我们在设计前后端进行数据交互的 api 接口时,需要符合 restful 规范,它是一种写前后端分离的标准

对于REST这种面向资源的架构风格,有人提出一种全新的结构理念,即:面向资源架构(ROA:Resource Oriented Architecture)

10条 restful 规范:

1、通信协议一般使用 https 协议,为保障数据安全

2、设计的接口地址是可以让人一眼看出来是 api 接口(在接口中带api字眼)

  • https://api.baidu.com/books
  • https://127.0.0.1:8080/api/books

3、多数据版本共存

接口更新之后,老版本的接口依旧一起使用,等过了期限才弃用老版本(维护老版本接口),以便可以留存更多用户。

  • https://api.baidu.com/v1/login
  • https://api.baidu.com/v2/login

4、交互数据即是资源,使用名词(可以是复数)

  • https://api.baidu.com/v1/users
  • https://api.example.com/v1/animals

不建议使用动词,如 get_resource ,除非是 login 或者 register 这种接口

  • https://api.baidu.com/v2/login

5、用不同的请求方式表示不同的资源操作

  • get: 获取资源
  • post: 新增资源
  • put: 修改资源(全局修改)
  • patch: 修改资源(局部修改)
  • delete: 删除资源

6、过滤,通过在url上传参的形式传递搜索条件

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

7、响应状态码(http的响应状态码,响应体的json数据中带状态码)

http 协议的状态码:

更多状态码请参考: https://www.cnblogs.com/elijah-li/p/16069638.html

1xx:请求正在处理
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 - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。

更多状态码请参考: https://www.cnblogs.com/elijah-li/p/16069638.html

服务端自定义的状态码

响应体中返回json格式数据,数据中有 服务端自定义的状态码(code,status)

  • 1001 :用户名错误
  • 1002 :没有权限

8、返回错误信息(错误处理)

返回数据是json格式,带状态码和错误信息

{
    code: 1002
    error: "Invalid API key"
}

9、不同的请求方式(不同操作)应该返回不同的资源

  • get:/collection/resources 获取多个资源 --》 返回资源对象的列表 [{name:elijah,age:18},{name:pyy,age:33}]
  • get /collection/resource 返回单个资源对象 {name:elijah,age:18}
  • post: 新增资源 --》 返回新增的资源对象 {name:elijah,age:18}
  • put: 修改资源(全局修改) --》 返回修改的资源对象 {name:elijah,age:18}
  • patch: 修改资源(局部修改) --》 返回修改的资源对象 {name:elijah,age:18}
  • delete: 删除资源 --》 返回空文档(或者错误文档) {code:100,msg:删除成功}

10、返回资源中要跳转的链接地址

{"link": {
  "rel":   "collection https://www.example.com/zoos",
  "href":  "https://api.example.com/zoos",   """连接地址"""
  "title": "List of zoos",
  "type":  "application/vnd.yourformat+json"
}}

drf 的安装与使用

1、安装 djangorestframework

pip install djangorestframework==3.10.3

2、在 settings.py 文件中 注册 rest_framework

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "app01.apps.App01Config",
    "rest_framework",
]

3、在 models.py 中写表模型

class Book(models.Model):
    name = models.CharField(verbose_name="书名", max_length=32)
    price = models.DecimalField(verbose_name="价格", max_digits=5, decimal_places=2)
    author = models.CharField(verbose_name="作者", max_length=32)

    class Meta:
        verbose_name_plural = "书籍表"

4、新建一个序列化类

在应用文件夹下创建一个 ser.py 作为序列化模块

from rest_framework.serializers import ModelSerializer
from app01.models import Book


class BookModelSerializer(ModelSerializer):  # 继承的是 ModelSerializer
    class Meta:
        model = Book
        fields = "__all__"  # 注意别漏写 fields

5、书写视图函数(CBV)

from rest_framework.viewsets import ModelViewSet
from .ser import BookModelSerializer, Book


# Create your views here.


class BookModelViewSet(ModelViewSet):  # 继承的是 ModelViewSet
    queryset = Book.objects.all()
    serializer_class = BookModelSerializer

6、书写 url

from app01 import views
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register("books", views.BookModelViewSet)


urlpatterns = [
    path("admin/", admin.site.urls),
]
urlpatterns += router.urls

9、迁移数据库

python manage.py makemigrations
python manage.py migrate

10、在浏览器中测试接口

image

11、在 postman 中测试接口

注意: 在发送 put 请求(修改资源)、patch 请求(修改资源)、delete 请求(删除资源)时,得在名词后面添加具体的资源 id 值,并且要加上 “/” ,因为 postman 不会自动加斜杆

获取资源

image

新增资源:

image

修改资源:

image

删除资源:

image

cbv 的 View 源码分析

从路由文件 urls.py 的调用语句中看起

urlpatterns = [
    path("CBV/", views.MyClass.as_view()),
]
# as_view() 函数加括号优先调用 as_view函数

按住 ctrl 键,鼠标点击查看 as_view 源码

@classonlymethod
def as_view(cls, **initkwargs):
    def view(request, *args, **kwargs):
        self = cls(**initkwargs)		# self 是我们自定义类产生的对象
        if hasattr(self, "get") and not hasattr(self, "head"):
            self.head = self.get
        self.setup(request, *args, **kwargs)
        if not hasattr(self, "request"):	# 自定义类必须接收 request 对象,否则主动报错
            raise AttributeError(
                "%s instance has no "request" attribute. Did you override "
                "setup() and forget to call super()?" % cls.__name__
            )
         return self.dispatch(request, *args, **kwargs)		# view 函数调用 View 类中的dispath函数
    # ... 中间省略部分源码
    return view		# 返回view函数对象

从源码中可以看出,as_view 调用之后得到的是 view 函数对象,这是个闭包函数,当视图函数被触发,调用的是 view函数,view函数return一个 dispatch 函数调用结果

我们再查看 dispatch 的源码:

http_method_names = ["get", "post", "put", "patch", "delete", "head", "options", "trace"]


def dispatch(self, request, *args, **kwargs):
    # Try to dispatch to the right method; if a method doesn"t exist,
    # defer to the error handler. Also defer to the error handler if the
    # request method isn"t on the approved list.
    if request.method.lower() in self.http_method_names:	# 如果是request中的属性,则用反射调用自身的响应的函数
        handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
    else:
        handler = self.http_method_not_allowed
    return handler(request, *args, **kwargs)

APIView 源码分析

APIView 是 rest_framework.views 中的一个类,是 drf 提供给我们更多功能的视图函数类,也继承了 Django 的 View

基于 CBV 先定义一个视图函数

views.py :

from rest_framework.views import APIView

class BookAPIView(APIView):
    def get(self, request):
        pass

    def post(self, request):
        pass

urls.py :

urlpatterns = [
    path("admin/", admin.site.urls),
    path("book/",views.BookAPIView.as_view())  # 调用 as_view() 返回的是 view 函数的内存地址
]

调用的是 APIView 的 as_view 方法:

APIView 类继承的是 Django 的 View,所以 super().as_view(**initkwargs) 调用了父类(View)中的 as_view,返回的是 View 中 as_view 返回的 view,在 view 函数里调用的 self.dispatch(request, *args, kwargs) 根据类的查找顺序,调用的就是 APIView 中的 dispatch

class APIView(View):
    @classmethod
    def as_view(cls, **initkwargs):
        view = super().as_view(**initkwargs)
        view.cls = cls
        view.initkwargs = initkwargs
        return csrf_exempt(view)  # 所有继承了 APIView 的视图函数都忽略了 csrf 认证
  • 调用了 APIView 的 dispatch方法
  • 忽略了视图函数的 csrf 认证
csrf_exempt(index) 相当于
@csrf_exempt
def index(request)
	pass
# index=csrf_exempt(index)

APIView 中的 dispatch:

    def dispatch(self, request, *args, **kwargs):
        # 重写了 Django 传过来的 request 请求数据对象,给request增添了新属性
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request

        try:
            # 进行三大认证
            self.initial(request, *args, **kwargs)
            # 反射机制调用视图函数类中的方法,与原生 dispatch 一致
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed
            respOnse= handler(request, *args, **kwargs)
        except Exception as exc:
            respOnse= self.handle_exception(exc)

        # 处理放回数据,具有 drf 特色的页面
        self.respOnse= self.finalize_response(request, response, *args, **kwargs)
        return self.response

APIView 中的 initialize_request:

对原生的 request 进行处理,新增了一些功能和属性

    def initialize_request(self, request, *args, **kwargs):
        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_cOntext=parser_context
        )

initialize_request 中的 Request():

把原生的 request 赋给了 _request,原 request 请求对象的方法在 _request 中获取就可以

class Request:
    def __init__(self, request, parsers=None, authenticators=None,
                 negotiator=None, parser_cOntext=None):

        self._request = request
        self._data = Empty
request 的变化

新的:
老的:

三大认证:

# 三大认证人如何走的
self.initial(request, *args, **kwargs)---》APIView的
核心代码:
   self.perform_authentication(request)  # 认证
   self.check_permissions(request)   #权限
   self.check_throttles(request) # 频率

drf 的 Request 类

重写了 request 请求数据对象之后,原生的 request 方法一样能用,因为 Request 类中的 getattr 方法(对象的 "." 点拦截)中用放射机制获取了原生 request 的所有属性

Request --> __getattr__

    def __getattr__(self, attr):
        try:
            return getattr(self._request, attr)
        except AttributeError:
            return self.__getattribute__(attr)

前端post请求传入的数据,在原来的request.POST中只能处理urlencoded和formdata编码格式,json格式不能处理。

而 Request 类实例化之后,提供了一个 data 方法,无论前端用什么编码post提交的数据,都从 request.data 中获取。

    @property
    def data(self):
        if not _hasattr(self, "_full_data"):
            self._load_data_and_files()
        return self._full_data

推荐阅读
  • 本文介绍了如何使用JavaScript的Fetch API与Express服务器进行交互,涵盖了GET、POST、PUT和DELETE请求的实现,并展示了如何处理JSON响应。 ... [详细]
  • 在寻找轻量级Ruby Web框架的过程中,您可能会遇到Sinatra和Ramaze。两者都以简洁、轻便著称,但它们之间存在一些关键区别。本文将探讨这些差异,并提供详细的分析,帮助您做出最佳选择。 ... [详细]
  • 构建Filebeat-Kafka-Logstash-ElasticSearch-Kibana日志收集体系
    本文介绍了如何使用Filebeat、Kafka、Logstash、ElasticSearch和Kibana构建一个高效、可扩展的日志收集与分析系统。各组件分别承担不同的职责,确保日志数据能够被有效收集、处理、存储及可视化。 ... [详细]
  • 本文探讨了为何采用RESTful架构及其优势,特别是在现代Web应用开发中的重要性。通过前后端分离和统一接口设计,RESTful API能够提高开发效率,支持多种客户端,并简化维护。 ... [详细]
  • 在使用Postman进行接口测试时,如果携带大量参数,可能会遇到‘请求头过大’的问题。本文将详细介绍如何调整Tomcat的请求头大小限制,并提供有效的路径映射解决方案,以避免因路径配置不当导致的404错误。 ... [详细]
  • 为了解决不同服务器间共享图片的需求,我们最初考虑建立一个FTP图片服务器。然而,考虑到项目是一个简单的CMS系统,为了简化流程,团队决定探索七牛云存储的解决方案。本文将详细介绍使用七牛云存储的过程和心得。 ... [详细]
  • ssm框架整合及工程分层1.先创建一个新的project1.1配置pom.xml ... [详细]
  • 深入解析 Android IPC 中的 Messenger 机制
    本文详细介绍了 Android 中基于消息传递的进程间通信(IPC)机制——Messenger。通过实例和源码分析,帮助开发者更好地理解和使用这一高效的通信工具。 ... [详细]
  • 探讨ChatGPT在法律和版权方面的潜在风险及影响,分析其作为内容创造工具的合法性和合规性。 ... [详细]
  • 本文介绍了一个基于 Java SpringMVC 和 SSM 框架的综合系统,涵盖了操作日志记录、文件管理、头像编辑、权限控制、以及多种技术集成如 Shiro、Redis 等,旨在提供一个高效且功能丰富的开发平台。 ... [详细]
  • Django Token 认证详解与 HTTP 401、403 状态码的区别
    本文详细介绍了如何在 Django 中配置和使用 Token 认证,并解释了 HTTP 401 和 HTTP 403 状态码的区别。通过具体的代码示例,帮助开发者理解认证机制及权限控制。 ... [详细]
  • 本文深入探讨了UNIX/Linux系统中的进程间通信(IPC)机制,包括消息传递、同步和共享内存等。详细介绍了管道(Pipe)、有名管道(FIFO)、Posix和System V消息队列、互斥锁与条件变量、读写锁、信号量以及共享内存的使用方法和应用场景。 ... [详细]
  • JMeter使用指南与性能测试实践
    本文详细介绍了JMeter的功能特点及应用场景,包括其作为开源、免费且基于Java开发的压力测试工具的优势。文章还涵盖了JMeter的安装配置过程以及如何进行简单的性能测试,旨在帮助初学者快速掌握JMeter的使用。 ... [详细]
  • 本文介绍了Elasticsearch (ES),这是一个基于Java开发的开源全文搜索引擎。ES通过JSON接口提供服务,支持分布式集群管理和索引功能,特别适合大规模数据的快速搜索与分析。 ... [详细]
  • HTTP中的Chunked编码与Content-Length的区别及应用场景
    本文探讨了在HTTP协议中,当使用Transfer-Encoding为chunked时为何无需设置Content-Length,以及这种编码方式的具体实现和优势。 ... [详细]
author-avatar
Viola大人
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有