视图家族案例
视图家族案例
一、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)
在当下的阶段,必将由程序员来主导,甚至比以往更甚。