视图家族案例

视图家族案例

一、models.py模型类

from django.db import models
class Student(models.Model):
    name = models.CharField(max_length=65)
    age = models.IntegerField(null=True)

二、serializers自定义序列化类

from rest_framework import serializers
from . import models
class StudentSerializers(serializers.ModelSerializer):
    class Meta:
        model = models.Student

        fields = ("name", "age")

三、路由匹配

from django.conf.urls import url
from . import views

urlpatterns = [
    # url(r'^admin/', admin.site.urls),
    # 第一个版本什么也没继承,就是原生的操作
    url(r'^v1/students/$', views.StudentAPIView.as_view()),
    url(r'^v1/students/(?P<pk>\d+)/$', views.StudentAPIView.as_view()),

    # 第二版本继承了GenericAPIView类实现了群查
    url(r'^v2/students/$', views.StudentGenericAPIView.as_view()),

    url(r'^v2/students/(?P<pk>\d+)/$', views.StudentGenericAPIView.as_view()),

    # 第三个版本继承了GenericAPIView类和工具类实现了群查
    url(r'^v3/students/$', views.StudentMixinGenericAPIView.as_view()),

    url(r'^v3/students/(?P<pk>\d+)/$', views.StudentMixinGenericAPIView.as_view()),

    # 第四个版本工具视图类继承了rest_framework.generics具体实现的功能
    url(r'^v4/students/$', views.StudentMixinListAPIView.as_view()),

    url(r'^v4/students/(?P<id>\d+)/$', views.StudentMixinListAPIView.as_view()),

    # 第五个版本工具视图集类继承了ModelViewSet实现了具有六大功能
    # 将所有请求方式与响应方法名,通过映射关系交给用户自己配置
    url(r'^v5/students/$', views.StudentModelViewSet.as_view(
        {
            "get": "list",
            "post": "my_post"
        }
    )),

    # 将所有请求方式与响应方法名,通过映射关系交给用户自己配置
    url(r'^v5/students/(?P<pk>\d+)/$', views.StudentModelViewSet.as_view(
        {
            "get": "retrieve",
            "put": "update",
            "patch":"partial_update",
            "delete":"destroy"
        }
    )),

]

四、视图类

from . import models
from .serializers import StudentSerializers
from utilss.MyResponse import APIResponse
# 视图家族
from rest_framework import views, generics, mixins, viewsets
"""
views: 视图类,
mixins: 视图工具类
generics: 工具视图类
viewsets: 视图集
"""
from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView
# 两大视图类: APIView, GenericAPIView
# 六大视图工具类
from rest_framework.mixins import RetrieveModelMixin, \
    ListModelMixin, \
    CreateModelMixin, \
    UpdateModelMixin, \
    DestroyModelMixin

"""
六大视图工具类:
    RetrieveModelMixin,\  单查
    ListModelMixin,\  群查
    CreateModelMixin,\ 单增
    UpdateModelMixin,\ 单更改,局部更改
    DestroyModelMixin 删除,自己写
"""
from rest_framework import generics
# 九大工具视图类:...
from rest_framework import viewsets
# 两大视图集基类:ViewSet、GenericViewSet
# APIView继承Django的View
"""
1.View 将请求方式与视图类的同名方法建立映射,完成请求响应
2. APIView:
    view的功能:
    重写as_view禁用了csrf认证
    重写dispatch:请求、响应、渲染、异常、解析、三大认证
    多了一堆类属性,可以完成视图类的局部配置
    
"""
from api02.serializers import StudentSerializers
class StudentAPIView(APIView):
    def get(self, request, *args, **kwargs):
        student_list_obj = models.Student.objects.all()
        student_list = StudentSerializers(student_list_obj, many=True)

        return APIResponse(1, "data ok", results=student_list.data)

# 3) GenericAPIView
#  GenericAPIView 继承了APView类,具有他的全部功能
# GenericAPIView提供了三个方法: get_object()、get_queryset()、get_serializer_class()
"""
 三个方法两个属性
 get_object(): 获取orm查询的类对象 ,Student object
 get_queryset(): orm对象数据中的结果集, models.Student.objects.all() <QuerySet [<Student: Student object>, <Student: Student object>]>
 get_serializer_class(): 获取序列化类,自定义的序列化类
 get_serializer(): 获取序列化类产生的结果
 这个几个方法都依赖于:
    queryset = models.Student.objects.all()
    serializer_class = StudentSerializers
"""

class StudentGenericAPIView(GenericAPIView):
    """
    群查序列化
    1)
    student_list_obj = models.Student.objects.all()将这一句话转换了两句话,看源码
    设置类属性GenericAPIView中的queryset的值
    queryset = models.Student.objects.all()
    获取orm查询的对象结果
    stu_query = self.get_queryset()
    2)
    将一句话变成了两句话
    student_list = StudentSerializers(student_list_obj, many=True)
    设置自己序列的类
    serializer_class = StudentSerializers
    获取序列化类的结果
    stu_ser = self.get_serializer(stu_query, many=True),调用了get_serializer_class获取序列化的类

    把原先可以一步完成的事情分成了两部分
    """
    queryset = models.Student.objects.all()
    serializer_class = StudentSerializers

    def get(self, request, *args, **kwargs):
        print(self.get_object())
        print(self.get_queryset())
        print(self.get_serializer())
        print(self.get_serializer_class())

        stu_query = self.get_queryset()
        stu_ser = self.get_serializer(stu_query, many=True)
        return APIResponse(results=stu_ser.data)

# 第三个版本
from rest_framework import mixins

"""
视图工具类mixins
提供了群查,单增,单删等方法六大方法
群查
mixins.ListModelMixin
"""

class StudentMixinGenericAPIView(mixins.ListModelMixin, mixins.CreateModelMixin, GenericAPIView):
    queryset = models.Student.objects.all()
    serializer_class = StudentSerializers
    # 群查
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    # 单增
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

# GenericViewSet第二大视图类
# 与generics: 工具视图类
from rest_framework.generics import CreateAPIView, ListAPIView, ListCreateAPIView, RetrieveAPIView, UpdateAPIView, \
    DestroyAPIView


#  工具视图类六大功能              单增            群查
class StudentMixinListAPIView(CreateAPIView, RetrieveAPIView, ListAPIView, UpdateAPIView, DestroyAPIView):
    """mixins.CreateModelMixin,
                    GenericAPIView

    都继承GenericAPIView视图类
    对用的功能列继承了对应工具mixins里面对应的类
    1. CreateAPIView 单增
    2. ListAPIView 群查
    3. ListCreateAPIView 群查和单增
    4 RetrieveAPIView 单增
    5 UpdateAPIView 单改 put/patch 提供了整体改和局部改,
    6 DestroyAPIView 单删一定要重写destroy方法因为他是将一条记录删除,所以要自己写字段删除功能

    单查和群查不能同时出现,因为都是get方法,只能同时访问一个
    """
    #           orm查询语句
    queryset = models.Student.objects.all()
    serializer_class = StudentSerializers
    # GenericAPIView中提供lookup_field 主要是为了url中单查,提供的不一定是主键,所以提供的是数据库中的唯一主键字段名就可以
    lookup_field = "id"

    # lookup_url_kwarg # 查找数据中的唯一键

    # 有删除需求的接口继承DestroyAPIView,重写destroy完成字段删除
    def destroy(self, request, *args, **kwargs):
        # 字段删除
        pass

# 视图工具集
from rest_framework.viewsets import ModelViewSet
class StudentModelViewSet(ModelViewSet):
    """
    六大功能具有
    ViewSetMixin重写as_views()方法通过反射机制实现对应功能的请求
    as_views()完成了请求自定义映射,将所有请求方式与响应方法名,通过映射关系交给用户自己配置
    一般单查和群查共存使用继承 ReadOnlyModelViewSet类

    GenericViewSet类作为ReadOnlyModelViewSet的父类类作为ReadOnlyModelViewSet的父类,实现继承工具类中的单查和群查的方法
    ViewSet和GenericViewSet类的区别:登录接口post不需要增
    所以GenericViewSet标准的资源接口post请求一定会往数据库中增,ViewSet他是非资源接口post不需要数据库增数据的交互
    """
    queryset = models.Student.objects.all()
    serializer_class = StudentSerializers

    def my_post(self, request, *args, **kwargs):
        return APIResponse(1, "my post ok")

# 实现登录接口
class LoginAPIView(APIView):
    # post请求不会向数据库增加数据
    pass

class LoginGenericAPIView(GenericAPIView):
    # 一定要添加这两句话,并且要post请求一定会将数据保存到数据中
    queryset = ''
    serializer_class = ''

五、UpdateAPIView局部修改密码

# 1.修改密码, 一定要以pk接收
re_path(r'modify_pwd/(?P<pk>.*)$', views.ModifyPwdAPIView.as_view()),
# 2. 重置密码序列化
class ModifyPwdAPIView(UpdateAPIView):
    authentication_classes = [JSONWebTokenAuthentication]
    queryset = models.User.objects.all()
    serializer_class = serializers.ModifyPwdSerializer

# 3.序列化类
class ModifyPwdSerializer(serializers.ModelSerializer):
    code = serializers.CharField(max_length=10, write_only=True)

    class Meta:
        model = models.User
        fields = (
            'password',
            'phone',
            'code',

        )

    def validate(self, attrs):
        code = attrs.pop('code')
        phone = attrs.pop('phone')
        catch_code = cache.get(f"{settings.SMS_CACHE_KEY}{phone}")
        # 获取用户,底层已经给你封装了可以直接获取
        user_obj = self.context.get("request").user

        print(user_obj.phone)
        if phone != user_obj.phone:
            serializers.ValidationError({'phone': "手机号有误,请确认手机号"})

            # 判断两次密码是否一样
        elif code != catch_code:
        
             raise serializers.ValidationError({"code": "验证码有误"})
        
         # 清除一次性验证码,使用过一次就不可以使用
         cache.set(f"{settings.SMS_CACHE_KEY}{phone}", "0000", 0)

        print(attrs)
        return attrs

   # User表必须重写update方法,才能操作密文密码
    def update(self, instance, validated_data):
        password = validated_data.get('password')
        instance.set_password(password) # 修改密码
        print(instance.password)
        return instance

重写UpdateModelMixin类中update方法实现自定义返回数据

 def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}

        return APIResponse(request=serializer.data)

img

posted @ 2020-02-10 21:05  RandySun  阅读(217)  评论(0编辑  收藏  举报