Rest Framework教程

本文是关于Django Rest Framework的教程,涵盖了序列化、请求与响应、基于类的视图、认证和权限等方面。通过示例介绍了如何创建serializers、views、URL配置,以及如何实现认证和权限控制。此外,还讨论了ViewSet和路由器的使用,帮助开发者更高效地开发Web API。

Home

要求
python版本3.6以上
Django版本 (2.2, 3.0, 3.1, 3.2, 4.0, 4.1)

安装

pip install djangorestframework

快速开始

  • 设置

创建tutorial 的新django项目,然后启动一个名为 quickstart 的新app。

创建一个新项目和一个单个应用
django-admin.py startproject tutorial .  # 注意结尾的'.'符号
cd tutorial
django-admin.py startapp quickstart

然后直接同步数据库, 创建用户

python manage.py migrate
python manage.py createsuperuser
  • Serializers

我们创建一个名为 tutorial/quickstart/serializers.py的文件,来用作我们的数据表示。
作用:
1.将queryset与model实例等进行序列化,转化成json格式,返回给用户(api接口)
2.将post与patch/put的上来的数据进行验证
3.对post与patch/put数据进行处理
简单来说,针对get来说,serializers的作用体现在第一条,但如果是其他请求,serializers能够发挥2,3条的作用

from django.contrib.auth.models import User, Group
from rest_framework import serializers


class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ('url', 'username', 'email', 'groups')


class GroupSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Group
        fields = ('url', 'name')
      
  • Views
from django.contrib.auth.models import User, Group
from rest_framework import viewsets
from tutorial.quickstart.serializers import UserSerializer, GroupSerializer


class UserViewSet(viewsets.ModelViewSet):
    """
    允许用户查看或编辑的API路径。
    """
    queryset = User.objects.all().order_by('-date_joined')
    serializer_class = UserSerializer


class GroupViewSet(viewsets.ModelViewSet):
    """
    允许组查看或编辑的API路径。
    """
    queryset = Group.objects.all()
    serializer_class = GroupSerializer
  • URLs
from django.conf.urls import url, include
from rest_framework import routers
from tutorial.quickstart import views

router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'groups', views.GroupViewSet)

urlpatterns = [
    url(r'^', include(router.urls))]

这样我们就可以进行数据接口访问啦http://127.0.0.1:8000/users/..

序列化

创建django项目,以及配置环境,就不细说了。创建snippetsapp
创建model,执行迁移

from django.db import models
from pygments.lexers import get_all_lexers
from pygments.styles import get_all_styles

LEXERS = [item for item in get_all_lexers() if item[1]]
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
STYLE_CHOICES = sorted((item, item) for item in get_all_styles())


class Snippet(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    title = models.CharField(max_length=100, blank=True, default='')
    code = models.TextField()
    linenos = models.BooleanField(default=False)
    language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
    style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)

    class Meta:
        ordering = ('created',)

开发我们的Web API的第一件事是为我们的Web API提供一种将代码片段实例序列化和反序列化为诸如json之类的表示形式的方式。我们可以通过声明与Django forms非常相似的序列化器(serializers)来实现。 在snippets的目录下创建一个名为serializers.py文件,并添加以下内容。

from rest_framework import serializers
from .models import Snippets, LANGUAGE_CHOICES, STYLE_CHOICES


class SnippetSerializer(serializers.Serializer):
    def create(self, validated_data):
        """
        根据提供的验证过的数据创建并返回一个新的`Snippet`实例。
        """
        return Snippets.objects.create(**validated_data)

    def update(self, instance, validated_data):
        """
        根据提供的验证过的数据更新和返回一个已经存在的`Snippet`实例。
        """
        instance.title = validated_data.get('title', instance.title)
        instance.code = validated_data.get('code', instance.code)
        instance.linenos = validated_data.get('linenos', instance.linenos)
        instance.language = validated_data.get('language', instance.language)
        instance.style = validated_data.get('style', instance.style)
        instance.save()
        return instance

    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(required=False, allow_blank=True, max_length=100)
    code = serializers.CharField(style={'base_template': 'textarea.html'})
    linenos = serializers.BooleanField(required=False)
    language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python')
    style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly')

然后创建view来测试。

  • ModelSerializers

我们的SnippetSerializer类中重复了很多包含在Snippet模型类(model)中的信息。如果能保证我们的代码整洁,那就更好了。

就像Django提供了Form类和ModelForm类一样,REST framework包括Serializer类和ModelSerializer类。

from rest_framework import serializers
from .models import PersonInfo


class PersonInfoSerializer(serializers.ModelSerializer):

    class Meta:
        model = PersonInfo
        fields = ['name', 'age', 'gender', 'address', 'phone_number', 'email']

向上面那样,我们在写serializers时候,可以直接继承model。
在这里插入图片描述
serializers.py

from rest_framework import serializers
from .models import PersonInfo


class PersonInfoSerializer(serializers.ModelSerializer):

    class Meta:
        model = PersonInfo
        fields = ['name', 'age', 'gender', 'address', 'phone_number', 'email']

然后view.py正常编写就可以。

请求与响应

  • 请求对象
    REST框架引入了一个扩展了常规HttpRequest的Request对象,并提供了更灵活的请求解析。Request对象的核心功能是request.data属性,它与request.POST类似,但对于使用Web API更为有用。

request.POST # 只处理表单数据 只适用于’POST’方法
request.data # 处理任意数据 适用于’POST’,'PUT’和’PATCH’方法

  • 响应对象
    REST框架还引入了一个Response对象,这是一种获取未渲染(unrendered)内容的TemplateResponse类型,并使用内容协商来确定返回给客户端的正确内容类型。

return Response(data) # 渲染成客户端请求的内容类型。

  • 状态码(Status codes)
    在你的视图(views)中使用纯数字的HTTP 状态码并不总是那么容易被理解。而且如果错误代码出错,很容易被忽略。REST框架为status模块中的每个状态代码(如HTTP_400_BAD_REQUEST)提供更明确的标识符。使用它们来代替纯数字的HTTP状态码是个很好的主意。

基于类的视图

APIView
内置了四种方法,可以根据请求方法写需求

class Desk(APIView):
    def get(self, request, **kwargs):
        print(kwargs)
        all_data = DeskInfo.objects.all()
        serializer = DeskInfoSerializer(all_data, many=True)

        return Response(serializer.data)

    def post(self, request, **kwargs):
        # 获取参数的三种方式
        # print(kwargs)
        # print(request.data)
        # print(request.query_params)
        color = request.data["color"]
        high = request.data["high"]
        desk = DeskInfo(color=color, high=high)
        desk.save()
        return Response({"ok"})

    def put(self, request):
        pass

    def delete(self, request, **kwargs):
        ob = DeskInfo.objects.get(pk=kwargs['pk'])
        ob.delete()
        return Response(status=status.HTTP_200_OK)

在这里插入图片描述
GenericAPIView(继承APIView)
GenericAPIView通常和mixins混合使用,这样我们在请求方法中,不用写具体操作,配合mixins的方法直接做到对数据的增删改查。
在这里插入图片描述

class Desk2(mixins.RetrieveModelMixin, mixins.CreateModelMixin, mixins.DestroyModelMixin, mixins.UpdateModelMixin, generics.GenericAPIView):
    queryset = DeskInfo.objects.all()
    serializer_class = DeskInfoSerializer

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, args, kwargs)

    def post(self, request, *args, **kwargs):
        return self.update(request, args, kwargs)

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, args, kwargs)

为了能够更简单,GenericAPIView的一些子类提供了内置的方法,所以我们不用写get等方法即可实现
在这里插入图片描述
以下代码,对应上面的表格,只能接受get请求,当使用get请求时,得到的内容就是查询所有。这样变得更为简单,我们无需写get方法。

class Desk3(generics.ListAPIView):
    queryset = DeskInfo.objects.all()
    serializer_class = DeskInfoSerializer

认证和权限

使用DRF开发了API,支持客户端以各种请求方式对资源进行增删查改。然而目前的 API 对谁可以新增、编辑或删除资源没有限制,希望通过基本的认证(Authentication)与权限(Permission)来实现一些更实用的功能:

只有经过身份验证的用户可以创建(匿名用户不允许通过POST提交新的)。
未经身份验证的请求应具有完全只读访问权限。
资源始终与创建者相关联,只有创建者可以更新或删除它。

区别
认证(Authentication)与权限(Permission)不是一回事。认证是通过用户提供的用户ID/密码组合或者Token来验证用户的身份。权限(Permission)的校验发生验证用户身份以后,是由系统根据分配权限确定用户可以访问何种资源以及对这种资源进行何种操作,这个过程也被称为授权(Authorization)。

我们编写好视图函数,定义serializer和url去访问, 可以发现,我们即使没登陆,也可以随意进行增删改查

class OrderDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = OrderInfo.objects.all()
    serializer_class = OrderSerializer
    # permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

在这里插入图片描述
当我们打开权限

  • permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

就可以发现未登录时只能查看了
在这里插入图片描述
DRF自带权限类
除了IsAuthenticatedOrReadOnly 类,DRF自带的常用权限类还包括:

IsAuthenticated类:仅限已经通过身份验证的用户访问;
AllowAny类:允许任何用户访问;
IsAdminUser类:仅限管理员访问;
DjangoModelPermissions类:只有在用户经过身份验证并分配了相关模型权限时,才会获得授权访问相关模型。
DjangoModelPermissionsOrReadOnly类:与前者类似,但可以给匿名用户访问API的可读权限。
DjangoObjectPermissions类:只有在用户经过身份验证并分配了相关对象权限时,才会获得授权访问相关对象。通常与django-gaurdian联用实现对象级别的权限控制。

我们也可以自定义权限, 我们创建一个permission文件,需要继承BasePermission,并根据需求重写has_permission(self,request,view)和has_object_permission(self,request, view, obj)方法。你还可以通过message自定义返回的错误信息。

from rest_framework import permissions


class IsOwnerOrReadOnly(permissions.BasePermission):

    message = "ni wu quan xian"

    def has_object_permission(self, request, view, obj):
        if request.method in permissions.SAFE_METHODS:
            return True
        # 将权限给创建的人
        return obj.rider == request.user

在views李导入即可。

class OrderDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = OrderInfo.objects.all()
    serializer_class = OrderSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly)

除此之外我们还能设置全局的权限,这样避免了每个视图都要重新写的麻烦。只需在setting里面设置即可。当你不想用全局的视图,可以直接在类试图写,或者通过装饰器来覆盖全局的。

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10,
    # 'DEFAULT_AUTHENTICATION_CLASSES': (
    #     'rest_framework.authentication.BasicAuthentication',
    #     'rest_framework.authentication.SessionAuthentication',
    # ),
    "DEFAULT_PERMISSION_CLASSES": (
        "rest_framework.permissions.IsAuthenticatedOrReadOnly",
    )
}
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

@api_view(['GET'])
@permission_classes((IsAuthenticated, ))
def example_view(request, format=None):
    content = {
        'status': 'request was permitted'
    }
    return Response(content)

视图集和路由器

ViewSet类与View类几乎相同,不同之处在于它们提供诸如read或update之类的操作,而不是get或put等方法处理程序。

最后一个ViewSet类只绑定到一组方法处理程序,当它被实例化成一组视图的时候,通常通过使用一个Router类来处理自己定义URL conf的复杂性

以下代码使用的viewset里面的ModelViewSet, 我们无需在定义查找详细,还是列出所有,他都已经帮我们定义好了。

class CarList(viewsets.ModelViewSet):
    queryset = CarInfo.objects.all()
    serializer_class = CarSerializer

可以看一下内部代码,说明他都已经内置了查询,创建更新删除等方法。
在这里插入图片描述
当我们调用查找所有的视图可以定义下面url

urlpatterns = [
    path('car/', CarList.as_view({'get': 'list'})),
    path('car/<int:pk>/', CarList.as_view({'get': 'retrieve'}))
]

但这样定义url较为麻烦,还是得将情况都定义出来。接下来我们就使用路由器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值