Skip to main content

微小的装饰器函数,可以更轻松地在 ~100 LoC 中使用 Django 构建 API

项目描述

django-api-装饰器

PyPI 版本 发布 提交
分米 dw

使用 Django 构建 API 的小装饰器函数更容易,大约 100 行(比这个 README 更短!)

目录

一、安装
二、 三、用法 它是如何工作 的 IV。相关图书馆 V.背景故事


安装

pip install django-api-decorators

预计您已经安装了 Django

兼容性

这最初是在带有 Python 2.7 的旧 Django 1.5 代码库中使用的。

应该与 Django 1.x-2.x 和 Python 2.7-3.x 一起使用

  • 可能也适用于 Django 0.95-0.99,没有检查任何早期版本的发行说明
  • 2to3说明没有什么要改的,所以应该兼容Python 3.x
  • 尚未确认这是否适用于早期版本的 Python。

如果您遇到兼容性问题或已确认版本兼容性,请提交 PR 或提交问题。


用法

@method_exclusive,每个文档字符串:Checks if request.method is equal to method, if not, returns a 405 not allowed response。例子:

from django_api_decorators import method_exlusive

@method_exclusive('GET')
def get_latest_public_posts(request):
    ...

@require_auth,每个文档字符串:Checks if the request was made by an authenticated user, and if not, returns a 401 unauthorized response。例子:

from django_api_decorators import method_exclusive, require_auth

@method_exclusive('GET')
@require_auth
def get_favorites(request):
    favs = request.user.favorites.all()
    ...

@require_auth通过在装饰器之上构建,可以为用户添加更多授权检查,例如针对特定用户类型。例如:

from functools import wraps

from django.http import HttpResponse
from django_api_decorators import require_auth

def tenant_exclusive(func):
    """
    Checks if the authenticated user is a tenant, and if not, returns a
    401 unauthorized response
    """
    @wraps(func)
    @require_auth
    def func_wrapper(request, *args, **kwargs):
        if not request.user.is_tenant():
            return HttpResponse(status=401)
        return func(request, *args, **kwargs)
    return func_wrapper

@clean_form,每个文档字符串:Cleans the data in the POST or GET params using the form_class specified. Responds with a 400 bad request if the form is invalid with the errors specified in the form as JSON. Adds the cleaned data as a kwarg (cd) to the decorated function。例子:

from django.shortcuts import get_object_or_404
from django_api_decorators import method_exclusive, clean_form, require_auth

from posts.models import Post
from posts.forms import AddFavForm

@method_exclusive('POST')
@clean_form(AddFavForm)
@require_auth
def add_fav(request, cd):
    post = get_object_or_404(Post, pk=cd['post_id'])
    request.user.favorites.add(post)
    ...

@clean_forms,每个文档字符串:Cleans the data in the POST or GET params using the form_class specified. Responds with a 400 bad request if any of the forms are invalid with the errors specified in the form as JSON. Adds the cleaned data as a kwarg (cd_list) to the decorated function。例子:

from django_api_decorators import method_exclusive, clean_forms, require_auth

from posts.models import Post
from posts.forms import CreatePostForm

@method_exclusive('POST')
@clean_forms(CreatePostForm, 'posts')
@require_auth
def bulk_create_posts(request, cd_list):
    post_list = []
    for data in cd_list:
        post_list.append(Post(
            user=request.user,
            cotent=data['content']
        ))
    Post.objects.bulk_create(post_list)

    ...

这个怎么运作

目前所有的装饰器只是对request对象进行检查,如果请求无效则提前返回,否则让下一个函数执行。它们中的一些在调用下一个函数时添加了一个关键字参数,以便可以在其中使用解释的数据(就像清理过的表单字典一样,它们是作为kwarg关键字添加的cd)。

我鼓励你阅读源代码,因为它比这个 README 短:)

相关图书馆

  • django-序列化模型
    • Django classes to make your models, managers, and querysets serializable, with built-in support for related objects in ~100 LoC

背景故事

这个库是在我处理Yorango的 ad-hoc API 并从 MPA 过渡到 SPA 时构建的。我不想为每个请求重复大量的身份验证、授权和验证代码,而是想更多地使用装饰器或中间件来干燥它。装饰器将允许我们为无效请求提供适当的 HTTP 状态代码的早期返回。结果,请求代码变得更容易推理,保证它只会在 authz/authn/etc 之后执行,并且更不容易出现意外错误,例如由于忘记授权检查而导致的安全问题。@method_exclusive, @require_auth, 以及更多特定于项目的装饰器是出于其中的一些需求而诞生的。

验证有点困难,因为我们在 MPA 中有许多现有的Django Form希望重用 API 中已有的类和验证代码,而不是重新编写,并希望保持相同的惯用风格. Django REST Framework 有“验证器”的概念,但它明显不同于 Django 的标准Form接口,需要您购买 DRF 的其他部分才能使用,例如序列化器。@clean_form为满足这些需求而诞生。后来@clean_forms被用来解决在一个 API 请求中出现多个相同表单的情况(例如,批量创建),有点类似于DjangoFormSet的工作方式,但要简单得多,并且需要的前端和后端代码的耦合要少得多。

这些都在生产中使用并取得了很好的效果,一些 API 方法只有 1 个装饰器,而另一些 API 方法有 3 个或更多装饰器,例如:

@method_exclusive('POST')
@clean_form(CreateBillsForm)
@clean_forms(BillForm, 'bills')
@landlord_saas_exclusive
@authorize_action(Listing, 'listing_id')
def create_bills(request, cd, cd_list, listing):
    ...

    # bulk_create the new list of Bills
    bill_list = []
    for data in cd_list:
        bill_list.append(Bill(
            listing=listing,
            price=data['price'],
            due_date=data['due_date'],
        ))
    Bill.objects.bulk_create(bill_list)

    ...

一直想提取和开源这个以及我在 Yorango 制作的其他各种有用的实用程序库,终于有机会了!

项目详情


下载文件

下载适用于您平台的文件。如果您不确定要选择哪个,请了解有关安装包的更多信息。

源分布

django-api-decorators-0.0.3.tar.gz (6.4 kB 查看哈希)

已上传 source

内置分布

django_api_decorators-0.0.3-py2.py3-none-any.whl (5.9 kB 查看哈希)

已上传 py2 py3