使用装饰器管理调用请求

举报
码乐 发表于 2024/04/04 10:29:54 2024/04/04
【摘要】 1 装饰器:管理api的请求和提交在python中,人们经常使用装饰器来为对象增加或修改功能,比如初始化一个类时,某些属性可能需要很长计算时间, 此时,我们在python中可以创建一个装饰器类。只有在实际使用时,才去创建这个类的属性.或者一个方法装饰器,它在函数周围应用记忆缓存,做为延迟缓存,而不是延迟结果本身。或者一些通用函数装饰器, 将一个函数转换成一个泛型函数,它可以有不同的行为,...

1 装饰器:管理api的请求和提交

在python中,人们经常使用装饰器来为对象增加或修改功能,比如初始化一个类时,某些属性可能需要很长计算时间, 此时,我们在python中可以创建一个装饰器类。只有在实际使用时,才去创建这个类的属性.

或者一个方法装饰器,它在函数周围应用记忆缓存,做为延迟缓存,而不是延迟结果本身。

或者一些通用函数装饰器, 将一个函数转换成一个泛型函数,它可以有不同的行为,其具体行为取决于其第一个参数的类型。

这里简单对比几个框架使用装饰器实现管理路由的方式

1.1 示例:方法装饰 property,classmethod和staticmethod: 方法装饰器

  • 装饰器 property:

@property是当您想为对象中的属性定义 getter 和 setter 时使用的装饰器。Getter 和 setter 提供了一种在尝试读取或修改对象的属性时添加验证或运行一些额外代码的方法。

这是通过将属性转换为一组函数来完成的:一个函数在您尝试访问该属性时运行,另一个在您尝试更改其值时运行。

  • 装饰器 classmethod:
    @classmethod可以在方法上使用以使其成为类方法:使其获得对类对象的引用,而不是实例(self)。

一个简单的例子是创建一个返回类名的函数:

staticmethod: @staticmethod用于将方法转换为静态方法:一种等效于位于类中的函数,独立于任何类或对象属性。使用它完全摆脱了self传递给方法的第一个参数。

1.2 示例:路由中的查询参数

声明不属于路径参数的其他函数参数时,它们将被自动解释为"查询字符串"参数 如下skip limit都是查询参数

返回json 格式,原始值 为字符串
限制查一个

    http://127.0.0.1:2000/items/?skip=0&limit=1   

限制查10个

    http://127.0.0.1:2000/items/?skip=0&limit=10  

skip: 对应的值为0
limit: 对应的值 10
参数原始值为 字符串,当你为它们声明一个Python类型时,
它们将转换为该类型并针对该类型进行校验

    @app.get("/items/")
    async def read_time(skip: int = 0, limit: int = 10):

        return fake_items_db[skip:skip + limit]

当你为它们声明了python类型,它们将转换为该类型并针对该类型进行校验。
应用于该路径参数的所有相同过程也适用于查询参数。

    编辑器支持
    数据解析
    数据校验
    自动生成文档
  • 装饰器的 默认值

查询参数可以有默认值 skip=0,limit=10 就是默认值。

  • 装饰器的 可选参数

使用设置None声明可选参数。

  • 装饰器的 多个路径参数和 查询参数

注意 如果 q 和 short 没有默认值 那就是必填查询参数,在这个例子中,有2个查询参数:

    user_id: int,  user_id 必须的int类型 路径参数。
    item_id:str    item_id 必须的str 类型 路径参数
    q,一个必须的 没有默认值的str 类型参数。
    short,一个可选的 bool 类型参数。
  • 装饰器的 多个路径参数 和 查询参数

      @app.get("/user/{user_id}/items/{item_id}")  
      async def read_user_check(user_id: int, item_id:str, q: Optional[str], short:bool=False):
    

q 是可选字符串参数 默认为 None。

FastAPI可以分辨 参数 item_id 是路径参数,而q不是,因此q是查询参数。

查询参数类型转换 声明不属于路径参数的其他函数参数时,它们将被自动解释为"查询字符串"参数

short: 是否排序

short=on 就是查询参数,FastAPI可以 识别 on,yes,True,true,1 为 python的True

    > http://127.0.0.1:2000/user/1/items/2?q=ok&short=false
    < response:
        {"item_id":"2","own_id":1,"q":"ok","description":"This is an amazing item that has a long description"}

1.3 路径管理的方法装饰器

tags 和 status_code 和 response_model

使用 status 快捷常量 HTTP_201_CREATED
使用 tags 为路径操作 添加标签,tag一般由 str组成的 list构成, 可以用于 api 接口分组

response_model 定义返回数据结构模型

    @app.post("/items/create", response_model=Item, status_code=status.HTTP_201_CREATED, tags=["items"])
    async def create_item(item:Item):
        return item

使用:
POST /items/create Create an item

如果 description参数 与接口的docs 都设置了,那么只会显示一个描述 默认为路径中定义的,

路径装饰器还支持高级设置通过参数opeeration_id 设置 要使用的OpenAPO operationId

但是需要确保每个操作路径的 opeeration_id都是唯一的。

剩余部分不会出现在文档中,但是其他工具(比如 Sphinx)可以使用剩余部分。

1.4 实践:路径管理的方法装饰器

在HTTP中通常使用 GET,POST 获取全部信息,和添加信息

我们可以通过api使用者的post请求体body 携带的 json参数来添加内容, 并通过get来获取内容。

  • 首先,修改视图模块 views

导入管理器api_view,视图管理装饰器,决定请求方式,
并且导入Response和status当有错误请求时的错误码定义,决定api返回的内容。employee/views.py

from rest_framework.decorators import api_view    
from rest_framework.response import Response   
from rest_framework import status         
import rest_framework
@api_view(['GET', 'POST'])
def blog_api_view(request):
    if request.method == "GET":
        serializer = TaskSerializer(EmployeeSign.objects.all(), many=True)
        return Response(serializer.data)
    elif request.method == 'POST':
        serializer = TaskSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
  • 然后,修改应用的 路由

添加路由

from .views import blog_api_view
#employee/urls.py 
        ...
        path('blogs_tasks/', blog_api_view, name='blog_api_view'),
        ...
  • PUT,DELETE 更新与删除任务信息

我们有时需要为某一个任务 进行更新或删除操作, 新增如下方法employee/views.py

        @api_view(['GET', 'PUT', 'DELETE'])
        def api_detail_view(request, pk=None):
            try:
                bapi = EmployeeSign.objects.get(pk)
            except:
                return Response(status=status.HTTP_404_NOT_FOUND)
            if request.method == 'GET':
                serializer = TaskSerializer(bapi)
                return Response(serializer.data)
            elif request.method == 'PUT':
                serializer = TaskSerializer(bapi, data=request.data)
                if serializer.is_valid():
                    serializer.save()
                    return Response(serializer.data)
                return Response(bapi.errors, status=status.HTTP_400_BAD_REQUEST)
            elif request.method =='DELETE':
                bapi.delete()
                return Response(status=status.HTTP_204_NO_CONTENT)
  • 更新和删除的url api路由employee/urls.py

      path('blogs_tasks/', blog_api_view, name='blog_api_view'),
      path('blogs_tasks/<int:pk>/', api_detail_view, name='api_detail_view'),
    

2 小结

在flask和FastAPI这类框架中,传递参数给路径操作装饰器,即可轻松地配置路径操作、添加元数据,但是多个方法可能叠加几层装饰器。

可以看到在django的插件框架中,个人认为其使用更加具有灵活性和也更加清晰。

看官们认为如何?

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。