Django笔记(六):DRF框架

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

RESTful接口常见规范

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

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

DRF安装

安装命令:

复制代码
pip install djangorestframework

settings.py注册:

python 复制代码
INSTALLED_APPS = [
    "rest_framework",
    ...
]

视图编写

app/views.py

python 复制代码
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

python 复制代码
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()),
]

访问指定路由后:

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

序列化操作

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

定义model,/app/models.py

python 复制代码
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)

python 复制代码
from django.contrib import admin
from app.models import Player
# Register your models here.

admin.site.register(Player)

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

python 复制代码
python manage.py createsuperuser

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

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

python 复制代码
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):

python 复制代码
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):

python 复制代码
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)

设置路由后,访问结果:

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):

python 复制代码
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函数。

如果是添加数据,则:

python 复制代码
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)

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

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

python 复制代码
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)

python 复制代码
urlpatterns = [
    path("players/<int:pk>/", views.PlayerDetailView.as_view()),
    ...
]

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

python 复制代码
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)
python 复制代码
urlpatterns = [
    path("players/<name>/", views.PlayerDetailView.as_view()),
    ...
]

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 |

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

python 复制代码
class PlayerDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Player.objects.all()
    serializer_class = PlayersModelSerializer
    lookup_field = "name"

言简意赅。

自定义返回数据

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

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

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

分页

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

python 复制代码
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):

python 复制代码
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)

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

相关推荐
数据智能老司机4 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机5 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机5 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机5 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
c8i6 小时前
drf初步梳理
python·django
每日AI新事件6 小时前
python的异步函数
python
使一颗心免于哀伤6 小时前
《设计模式之禅》笔记摘录 - 21.状态模式
笔记·设计模式
这里有鱼汤7 小时前
miniQMT下载历史行情数据太慢怎么办?一招提速10倍!
前端·python
databook16 小时前
Manim实现脉冲闪烁特效
后端·python·动效
程序设计实验室16 小时前
2025年了,在 Django 之外,Python Web 框架还能怎么选?
python