Rest:一种面向资源的架构,这是一种概念。

RestFul:遵守了rest风格的应用

Django采用FBV(function based view)DRF采用CBV (class based view)

两种应用广泛的接口规范restfulRPC

序列化:将数据转化为特定的格式;反序列化:将特定格式的数据还原为我们需要的数据。

小知识

一个类中的方法加上@property注解后,不需要加括号就能调用该方法,该方法叫做属性方法

面向对象

python万物皆对象

class A(object):
    name = "A的Name"
    def __init__(self, name, age):
        self.name = name
        self.age = age
a = A("a传入的name", 23)

在上面的代码示例中,a实例对象根据A类来创建了一片空间,**self**指的就是该实例化后的对象,而后执行__init__方法把self传入,将nameage进行初始化。即:

在实例化完毕后的对象中,只会初始化在创建它的类中出现的self.xxx的内容,不会出现其他任何内容。在访问a的属性时,会优先查找自己有的属性,如果没有会往上查找创建它的类中有没有,如果还没有继续往上访问父类中有没有。

在python中,万物皆对象,变量名和函数名都是对象,所以在调用实例对象的name()会直接报错,而不会去找类中有没有这个方法。

子类调用父类方法时不需要传入self,且父类中self就是子类(调用者)。可以理解为子类把父类的这个方法复制到自己的里面了

class Father:
    def __init__(self, name):
        self.name = name
    def say(self, age):
        print(f'我是{self.name} {age}, {self.age}')
class son(Father):
    age = 13
    def foo(self):
        self.say(12)
 
son1 = son('张三')
son1.foo()
 
-> 我是张三 12

Django采用CBV模式的源码解读

Django使用CBV模式,通过方法名来区分请求方式。使用方式如下:

# view.py
class LoginView(View):
    def get(self, request):
        return HttpResponse('get')
 
    def post(self, request):
        return HttpResponse('post')
 
# urls.py
    path('test/', views.LoginView.as_view()),

源码解读:Django在启动时执行LoginView继承的父类View中的as_view()方法,在该方法中,存在有一个view()方法,在收到前端的请求后就执行view()方法。

在该方法中,做了一个分发的操作。通过dispatch方法,来区分出是什么类型的请求(post、get等)来执行不同的方法。非常简单的一种源码。

如何给**dispatch**方法加点自己的代码?

LoginView(View)中,覆盖父类的方法dispatch,而后通过super().dispatch来把之前的代码放进来。

class LoginView(View):
    def dispatch(self, request, *args, **kwargs):
        print("添加代码")
        return super().dispatch(request, *args, **kwargs)

1. DRF的安装

pip install djangorestframework

settings.py中注册该组件

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
    'rest_framework'
]

2. DRF的使用

采用CBV模式,但不继承Django自带的View,继承DRF的APIView, 这个类继承了View,且重新定义了request,使得其可以正常解析前端发来的Json数据。

class LoginView(APIView):
 
    def get(self, request):
        return HttpResponse('get')
 
    def post(self, request):
        data = request.data
        print(data)
        return HttpResponse('post')

在重新定义的request中,可以通过request.data来获取前端post发送的json数据并解析为了python的字典。

request的一些属性

  1. .data 返回解析后的请求体数据,包含了对POST、PUT、PATCH请求方式解析后的数据
  2. .query_paramsrequest.get是一样的,只是名字变了。
  3. request._request获得Django自带的Request对象。

通过这种方式,我们可以轻松获取前端传来的数据。

2.1 序列化器进行序列化

序列化器用来辅助我们将Django查询来的数据序列化为json格式

首先创建一个关于models中类的序列化类,

from rest_framework import serializers
 
class MySerializer(serializers.Serializer):
    name = serializers.CharField()
    age = serializers.IntegerField()

通过这个序列化类,可以将数据库拿出来的数据进行序列化,注意需要使用DRF自带的Response

from rest_framework.response import Response
def post(self, request)
    student = Student.objects.all()
    serialzer = MySerializer(instance=students, many=True)
    return Response(serialzer.data)

在序列化类中,变量名是序列化后的json键名,也是在数据库中的字段名。如果你想要json返回的键名和数据库中的字段不一致,

names = serializers.CharField(source="name")

2.2 进行反序列化

在反序列化之前,需要对前端传来的数据进行校验。

def post(self, request):
    # 构建序列化器对象
    serializer = BookDetailView(data=request.data)
    try:
        # is_valid方法进行校验,若校验不成功则直接报错
        serializer.is_valid(raise_exception=True)
 
        return Response(serializer.validated_data)
    except Exception as e:
        return Response(serializer.errors)

is_valid方法执行中,会创建两个列表,一个是**serializer.validated_data**,一个是**serializer.errors**,若数据校验成功则数据被添加到前者,若校验失败则把错误原因添加到后者。

2.3 添加、删除、修改、查找

  1. 添加数据实现
def post(self, request):
    # 将传入的数据进行序列化并验证
    serializer = BookDetailView(data=request.data)
    try:
        serializer.is_valid(raise_exception=True)
        Book.objects.create(**serializer.validated_data)
        return Response(serializer.validated_data)
    except serializers.ValidationError as e:
        return Response(serializer.errors)

**serializer.data**是固定对于序列化对象实例化时传入的**instance****参数进行序列化。**在serializer.save()时,默认将自定义的create()方法返回的值作为了instance

  1. 修改数据实现
def put(self, request, id):
    # 将传入的数据进行序列化并验证
    serializer = BookDetailView(data=request.data)
    try:
        serializer.is_valid(raise_exception=True)
        Book.objects.filter(pk=id).update(**serializer.validated_data)
        return Response(serializer.validated_data)
    except:
        return Response(serializer.errors)

在上面的两种方法中,都是我们在put或者post方法中使用ORM操作了数据库添加数据,这不够优雅,还可以使用save()方法。

这是serializer.save()的源码,可以看到,该方法会通过检测instance是否有值来确定这是个新增还是修改。而后选择调用**create**还是**update**方法。这两个方法需要在序列化类中自己实现

class BookDetailView(serializers.Serializer):
    title = serializers.CharField(max_length=100)
    author = serializers.CharField(max_length=100)
 
    def create(self, validated_data):
        return Book.objects.create(**validated_data)
 
    def update(self, instance, validated_data):
        return Book.objects.filter(pk=instance.pk).update(**validated_data)

实现新增和修改,

def post(self, request):
    # 进行数据校验
    serializer = BookDetailView(data=request.data)
    try:
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.validated_data)
    except serializers.ValidationError as e:
        return Response(serializer.errors)
 
def put(self, request, id):
    # 将传入的数据进行序列化并验证, instance设置为需要修改的原数据,data为修改后的数据
    serializer = BookDetailView(instance=Book.objects.get(pk=id), data=request.data)
    try:
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.validated_data)
    except:
        return Response(serializer.errors)

2.4 ModelSerializer

原来的serializer序列化类只能自己手动去写字段和方法,而ModelSerializer序列化类可以根据models模型类来自动生成字段和方法。

class BookDetailView(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['title'] # 设置需要哪些字段
        exclude = ['author'] # 设置不需要哪些字段,这个设置与上面的设置冲突。

2.5 GenericAPIView

在代码中使用一些不写死的属性代替 序列化器和模型 ,用于提高代码的复用性,为下一步封装代码做准备。

在Post和Put中,

from rest_framework.generics import GenericAPIView
class LoginView(GenericAPIView):
    # 指定模型
    queryset = Book.objects.all()
    # 指定序列化器
    serializer_class = BookDetailView
 
    def post(self, request):
        # GenericAPIView借助queryset和serialzer_class来实例化serializer,传入的参数还是序列化器需要传入的参数
        serializer = self.get_serializer(data=request.data)
        try:
            serializer.is_valid(raise_exception=True)
            serializer.save()
            return Response(serializer.validated_data)
        except serializers.ValidationError as e:
            return Response(serializer.errors)
     def put(self, request, pk):
        # 将传入的数据进行序列化并验证
        serializer = self.get_serializer(instance=self.get_object(), data=request.data)
        try:
            serializer.is_valid(raise_exception=True)
            serializer.save()
            return Response(serializer.validated_data)
        except:
            return Response(serializer.errors)

需要注意的是,在put方法中,通过get_object()方法获取的需要修改的对象依赖于**pk**和有名传参的设置pk这个参数名根据lookup_field = 'pk'来自定义设置,默认是pk,有名传参这样设置

re_path(r'test/(?P<pk>\d+)', views.LoginView.as_view())

2.6 Minin混合类

在上面GenericAPIView类中,通过不写死属性来使得代码的复用性很强。所以DRF设置了各种类对重复的代码进行封装。

通过对各种类的多继承,来实现对一些方法的封装,以便在开发中直接使用

from rest_framework.mixins import CreateModelMixin, UpdateModelMixin, ListModelMixin
 
class LoginView(GenericAPIView, CreateModelMixin, ListModelMixin):
    queryset = Book.objects.all()
    # 指定序列化器
    serializer_class = BookDetailView
    # 指定查询集
    lookup_field = 'pk'
 
    def get(self, request):
        return self.list(self, request)
 
    def post(self, request):
        return self.create(self, request)
ListModelMixinlist(self, request)提供查询列表功能(对应 HTTP 的 GET 方法),返回模型的多条数据
CreateModelMixincreate(self, request)提供创建资源功能(对应 HTTP 的 POST 方法),新增一条模型数据
RetrieveModelMixinretrieve(self, request, pk)提供查询详情功能(对应 HTTP 的 GET 方法),返回单条模型数据(按主键查询)
UpdateModelMixinupdate(self, request, pk)partial_update(self, request, pk)提供更新资源功能(对应 HTTP 的 PUT/PATCH 方法),支持全量更新和部分更新
DestroyModelMixindestroy(self, request, pk)提供删除资源功能(对应 HTTP 的 DELETE 方法),删除指定主键的模型数据

2.7 Viewset

只读viewset:

2.8 ModelViewSet

高度封装的一种类,自动实现增删改查和路由的建立。

示例:

class SubTodoViewSet(viewsets.ModelViewSet):
    """
    子待办事项(SubTodo)的API视图集,提供CRUD功能
    """
    serializer_class = SubTodoSerializer
    filter_backends = [DjangoFilterBackend, filters.OrderingFilter]
    filterset_fields = ['status']
    ordering_fields = ['created_at', 'priority', 'title', 'updated_at']
    ordering = ['priority', '-created_at']  # 默认排序

可以填入的参数:

可以自己重写方法来实现自定义逻辑:

2.8 认证

2.9 自定义返回json格式

序列化器 - Django REST 框架 - Django REST 框架

相关文档

相关文档