Django笔记(六):DRF框架

前后端分离是互联网应用开发的标准使用方式,让前后端通过接口实现解耦,能够更好的进行开发和维护。

RESTful接口常见规范

在接口设计中,大家遵循一定的规范可以减少很多不必要的麻烦,例如url应有一定辨识度,可以加入api等关键词,路径中尽量不要含有动词,根据请求方式对业务逻辑进行划分等等,如:

请求方式 数据库操作 描述
GET SELECT 获取数据
POST CREATE 添加数据
PUT UPDATE 更新数据
DELETE DELETE 删除数据

DRF安装

安装命令:

pip install djangorestframework

settings.py注册:

INSTALLED_APPS = [
    "rest_framework",
    ...
]

视图编写

app/views.py

from rest_framework.views import APIView
from rest_framework.response import Response

class IndexView(APIView):
    def get(self, request):
        res = dict()
        res['mes'] = "success"
        res['data'] = 123
        return Response(res)

视图函数变成了视图类,需要继承APIView。可在类内部分别定义get,post等请求函数,视图会根据请求方式映射不同处理函数。

路由配置

每条路由对应一个视图函数,故需将视图类转为视图函数

urls.py

from django.contrib import admin
from django.urls import path
from app1 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.IndexView.as_view()),
]

访问指定路由后:

Django笔记(六):DRF框架_第1张图片

 DRF框架自带的接口界面很好看,也便于调试。

序列化操作

将数据库数据整理为接口返回数据的过程很繁琐,DRF简化了序列化操作。

定义model,/app/models.py

from django.db import models

# Create your models here.
class Player(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=20)

定义了player模型,两个字段id和name。为了方便后台操作,我们将其进行admin注册(app/admin.py)

from django.contrib import admin
from app.models import Player
# Register your models here.

admin.site.register(Player)

记得进行数据迁移!!!之后便可在admin管理界面看到Player表格,登录admin管理系统需要创建用户,创建命令:

python manage.py createsuperuser

按提示注册后,登录admin管理界面:

Django笔记(六):DRF框架_第2张图片

可以看到创建的表格,手动添加两条数据。如果我们希望返回所有player信息,视图应该这么写(app/views.py):

from rest_framework.views import APIView
from rest_framework.response import Response
from app1.models import Player

class PlayersView(APIView):
    def get(self, request):
        players = Player.objects.all()
        res = list()
        for p in players:
            t = dict()
            t["id"] = p.id
            t["name"] = p.name
            res.append(t)
        return Response(res)

 字段较少的时候无妨,字段太多的时候,这是个让人抓狂的操作。

可以先编写一个序列化类(app/serializer.py):

from rest_framework import serializers
from app1.models import Player

class PlayersModelSerializer(serializers.ModelSerializer):
    class Meta:
        model=Player
        # fields="__all__"
        fields = ("id", "name")

此类用于对Player进行序列化,Meta类中只需指明指定模型,以及想要序列化的字段即可,fields的all参数指所有字段。

视图修改(app/views.py):

from rest_framework.views import APIView
from rest_framework.response import Response
from app1.models import Player
from app1.serializers import PlayersModelSerializer

class PlayersView(APIView):
    def get(self, request):
        players = Player.objects.all()
        # 创建序列化对象,many指多条数据
        players_json = PlayersModelSerializer(players, many=True)
        print(players_json.data)
        # data返回序列化后的数据
        return Response(players_json.data)

设置路由后,访问结果:

Django笔记(六):DRF框架_第3张图片

ModelSerializer只是对模型进行序列化,如果对其以外复杂结构进行序列化,可以继承Serializer类,逐个字段进行手动编写,以及序列化嵌套等等,不在赘述。

Mixins类改进

Django的mixins实现了各种功能让其他函数继承,能够让用户用更少的代码操作模型,一般会配合GenericAPIView使用,Mixin有五类:

描述 请求方法
ListModelMixin 返回查询集列表,提供list方法 GET
CreateModelMixin 创建实例,提供create()方法 POST
RetrieveModelMixin 返回一个具体实例,提供retrieve()方法 GET
UpdateModelMixin 更新实例,提供update()方法 PUT、PATCH
DestoryModelMixin 删除实例,提供delete()方法 DELETE

同样实现上面返回player列表的功能,视图可以这样写(app/views.py):

from rest_framework import mixins, generics
from app1.models import Player
from app1.serializers import PlayersModelSerializer

class PlayersView(mixins.ListModelMixin, generics.GenericAPIView):
    queryset = Player.objects.all()
    serializer_class = PlayersModelSerializer
    def get(self, request):
        return self.list(request)

queryset和serializer_class是要操作的数据集合序列化类,GenericAPIView需要的参数。因为ListModelMixin提供了list函数,get请求视图的返回结果可以直接调用。这里的执行结果与上面相同。(如果queryset需要条件查询,需要重写get_queryset函数。

如果是添加数据,则:

from rest_framework import mixins, generics
from app1.models import Player
from app1.serializers import PlayersModelSerializer

class PlayersView(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView):
    queryset = Player.objects.all()
    serializer_class = PlayersModelSerializer
    def get(self, request):
        return self.list(request)
    def post(self, request):
        return self.create(request)

Django笔记(六):DRF框架_第4张图片

提供name参数即可添加成功。

另外三个Mixin类使用相同,因为要对指定数据进行修改,故需提供词条数据的pk(主键)来找到此条数据。(app/views.py)

class PlayerDetailView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin,
                       generics.GenericAPIView):
    queryset = Player.objects.all()
    serializer_class = PlayersModelSerializer
    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)
    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)
    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

路由需要提供pk参数:(urls.py)

urlpatterns = [
    path("players//", views.PlayerDetailView.as_view()),
    ...
]

如果想要通过其他字段查找数据,需要提供lookup_field参数,指明要查找的字段(查询结果多于一条时会报错)

class PlayerDetailView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin,
                       generics.GenericAPIView):
    queryset = Player.objects.all()
    serializer_class = PlayersModelSerializer
    lookup_field = "name"
    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)
    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)
    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)
urlpatterns = [
    path("players//", views.PlayerDetailView.as_view()),
    ...
]

Django笔记(六):DRF框架_第5张图片

 GenericAPIView类

GenericAPIView还有许多子类,直接将Mixins和GenericAPIView进行了组合,有这么多:

提供方法

CreateAPIView

post
ListAPIView get
RetrieveAPIView get
DestroyAPIView delete
UpdateAPIView put, patch
ListCreateAPIView get, post
RetrieveUpdateAPIView get, put, patch
RetrieveDestroyAPIView get, delete, patch
RetrieveUpdateDestroyAPIView get, put, delete, patch

 上面的试图类可以这么写:

class PlayerDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Player.objects.all()
    serializer_class = PlayersModelSerializer
    lookup_field = "name"

言简意赅。

自定义返回数据

DRF提供了自定义返回类,可以自己编写,也可以硬往里赛东西,比如:

def get(self, request, *args, **kwargs):
        res = dict()
        res["mes"] = "success"
        res["data"] = self.list(request, *args, **kwargs).data
        return Response(res)

把原来Response中的data取出来,重新塞点东西再返回。

Django笔记(六):DRF框架_第6张图片

分页

 DRF有三个分页方式,这里说一个PageNumberPagination,创建一个分页类(app/paginations.py):

from rest_framework.pagination import PageNumberPagination

class PlayerPagination(PageNumberPagination):
    page_size = 2 # 每页显示的数据数量
    max_page_size = 4 # 每页最多显示的数据数量
    page_size_query_param = "size" # 显示数量的变量名
    page_query_param = "page" # 页数的变量名
    """
        如果访问localhost/player/?page=2&size=3,则会返回以三条数据分页的第二页内容
    """

用户视图(app/views.py):

from rest_framework import mixins, generics
from app1.models import Player
from app1.serializers import PlayersModelSerializer
from app1.paginations import PlayerPagination

class PlayersView(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView):
    queryset = Player.objects.all()
    serializer_class = PlayersModelSerializer
    pagination_class = PlayerPagination
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

Django笔记(六):DRF框架_第7张图片

 尾

一般APIView配合序列化就能很好开发接口,Mixins和GenericAPIView少不了几行代码,且queryset和response部分限制较多,自定义覆盖原方法的代码也就差不多把少的几行代码补回了,如果需要分页功能,可以用GenericAPIView编写。

你可能感兴趣的:(Django笔记,笔记,django,python)