1. ApiView
定义一个cbc视图
class BookView (APIView):pass
re_path(r"books/$", views.BookView.as_view(),name = "books"),
re_path(r"books/$", views.类下的View.as_view(),name = "books"),
一单有请求进来访问books/: view(request) ========APIView 类下的dispatch( )执行
2.def dispatch():
# 初始化操作
( 1 )构造新的request:
self.request = self.initial_request( )
# self.request._request
# self.request.GET
# self.reqeust.data
( 2 ) 执行组件
# 认证,权限,频率
认证 : request.user
self.initial (request, *args , **kwargs)
# 认证组件,他调用了新创建的request.user方法
self.perform_authentication(request)
认证:request.user
self.initial(request,*args,**kwargs)
========# 认证组件
self.perform_authentication(request)
request.user
========
for authenticator in self.authenticators: {# toekn}
# 我取了self.authenticators 中的一个属性 for authenticator in self.authenticators: # [TokenAuth()]执行的返回值 try: # 意思就是你如果没有自定义这个类就会抛错 user_auth_tuple = authenticator.authenticate(self)# 我自定义的这个方法 except exceptions.APIException: self._not_authenticated() """ 有异常了 可以用rasie决定异常了该做什么 不过 即使没有异常 也可以raise来定义满足特定条件后抛弃什么异常 """ raise # 这个条件成立 if user_auth_tuple is not None: self._authenticator = authenticator # 赋值 [TokenAuth()] # <rest_framework.request.Request object at 0x036BC390> self.user, self.auth = user_auth_tuple # 自定义方法的返回值 赋值了给 user, auth return
# 权限组件
self.check_permissions(request)
========
# 这里我for循环了一个方法,这个方法就是我定义的那个类 for permission in self.get_permissions(): # <rest_framework.permissions.AllowAny object at 0x034F1810> # 我们得确认下 permission.has_permission(request, self) 发生了什么 if not permission.has_permission(request, self): self.permission_denied( request, message=getattr(permission, 'message', None) )
# 频率组件
self.check_throttles(request)
(3)分发:
# Get the appropriate handler method
if request.method.lower() in self.http_method_names:
# self = Publish,反射类中的get方法如果有我就封装到handler里面,如果你没有定义方法我我也就返回一个错误信息
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
# 也就是说这个地方要么就是调用我Publish的get方法和post方法,要不就抛错误信息
response = handler(request, *args, **kwargs)
4.序列化组件
1.serializers.Serializer 初级版
from django.shortcuts import render, HttpResponse, redirect from django.views import View from app01 import models from rest_framework.views import APIView # 一.定义一个反序列的类 from rest_framework import serializers from rest_framework.response import Response
# 为queryset, model对象做序列化,只要你定义了name和addr我都能给你反序列化 class PublishSerializers(serializers.Serializer): name = serializers.CharField() addr = serializers.CharField()
#使用 class PublishView(APIView): # 查询数据 def get(self, request): # first inquire database publish = models.Publisher.objects.all() # data put serializers data packging bs = PublishSerializers(publish, many=True) # many=True多个对象 # return return Response(bs.data) # 一对多 多对多的使用 class BookSerializers(serializers.Serializer): title = serializers.CharField() pub_date = serializers.DateField() # 反序列化一对多字段返回的是__str__数据 publish = serializers.CharField(source="publish.addr") # source 可以指定返回的一对多的字段 # authors=serializers.CharField(source="authors.all") # 指定序列化多对多的字段 authors = serializers.SerializerMethodField() # 多对多字段序列化方法,这个函数必须是get_authors,因为这个字段在是多对多 def get_authors(self, obj): temp = [] for obj in obj.authors.all(): temp.append(obj.name) return temp
#使用 class PublishView(APIView): # 查询数据 def get(self, request): # first inquire database book = models.Book.objects.all() # data put serializers data packging bs = BookSerializers(book, many=True) # many=True多个对象 # return return Response(bs.data)
bs = PublishModelSerializers(data=request.data, many=True) # post不需要定义many=Ture if bs.is_valid(): bs.save() # 保存
# 更多操作
ps = PublishModelSerializers(publish, data=request.data) # if ps pass verify if ps.is_valid(): ps.save() #更新
2.serializers.ModelSerialize 中级版
class BookModelSerializers(serializers.ModelSerializer): # 自定义publish字段超链接路径 # publish_url = serializers.HyperlinkedIdentityField(view_name='detailpublish', # lookup_field='publish_id', # lookup_url_kwarg='pk', # ) # publish = serializers.CharField(source="publish.id") """ # view_name参数 进行传参的时候是参考路由匹配中的name与namespace参数 # lookeup_field参数是根据在UserInfo表中的连表查询字段group_id # look_url_kwarg参数在做url反向解析的时候会用到 """ # 重写save中的create方法 # def create(self, validated_data): # # create 方法之前也可以单独pop在添加 # """ # author = validated_data.pop[title] # 然后再进行额外自己添加 # obj = Book.objecte.create(**validated_data) # obj.authors.add(*authors) # """ # publish_id = validated_data["publish"]["id"] # book = models.Book.objects.create(title=validated_data["title"], pub_date=validated_data["pub_date"], # publish=models.Publisher.objects.filter(pk=publish_id).first() # ) # book.authors.add(*validated_data["authors"]) # return book class Meta: model = models.Book # fields = ['id', 'title', 'pub_date', 'publish', 'authors'] fields = "__all__" depth = 0 ## 0 ~ 10 # 自动向内部进行深度查询,就是查询的比较详细 depth表示查询层数
5.视图组件
from rest_framework import serializers from rest_framework.response import Response from rest_framework import viewsets from django.views import View from app01 import models from rest_framework.views import APIView
# 版本1:
class PublishDetaiView(APIView): # 将这个pk设置成和lookup_url_kwarg='pk' 一样的值,不然加后缀会取不到值 def get(self, request, id): # id 不要放到request前面 # 查询数据库 publish = models.Publisher.objects.filter(pk=id) # 封装打包序列化数据 bs = PublishModelSerializers(publish, many=True) # many=True多个对象 # Response 会直接返回josn数据格式 ret = Response(bs.data) return ret # # 修改数据(前端指定id值后,在data中输入k:v即可change数据) def put(self, request, id): # inquire database publish = models.Publisher.objects.filter(pk=id).first() # data= form request.data client ps = PublishModelSerializers(publish, data=request.data) # if ps pass verify if ps.is_valid(): ps.save() return Response(ps.data) else: return Response(ps.errors) # 删除数据(功能还未实现) def delete(self, request, id): print(type(id), 5555555555555) models.Publisher.objects.filter(id=id).delete() return Response("删除成功")
# 版本 2
class BOOK(GenericAPIView, mixins.ListModelMixin): queryset = models.School.objects.all() serializer_class = app01_serializers.SchoolSerializer def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) class BOOK(GenericAPIView, mixins.RetrieveModelMixin, mixins.CreateModelMixin): queryset = models.School.objects.all() serializer_class = app01_serializers.SchoolSerializer def get(self, request, pk, *args, **kwargs): return self.retrieve(request, pk, *args, **kwargs) def post(self, request, *args, **kwargs): return self.create(request, *args, **kwargs
# 版本3 基于通用类
# 封装了3层 class AuthorView(viewsets.ModelViewSet): # queryset serializer 这两个方法一定要定义成这个不然取不到值 queryset = models.Author.objects.all() serializer_class = AuthorModelSerializers # 封装了3层 class AuthorDetaiView(viewsets.ModelViewSet): # authentication_classes = [TokenAuth] # queryset serializer 这两个方法一定要定义成这个不然取不到值 queryset = models.Author.objects.all() serializer_class = AuthorModelSerializers
# 版本四
re_path('^authors/$', views.AuthorView.as_view({"get": "list", "post": "create"})), # View(request) ======APIView:dispatch() re_path('^author/(?P<pk>d+)/$', views.AuthorDetaiView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
流程:
请求一旦访问/authors/:
View()
# Bind methods to actions # This is the bit that's different to a standard view for method, action in actions.items(): handler = getattr(self, action) # self.list self.creat setattr(self, method, handler) # self.get self.post
return self.dispatch(request, *args, **kwargs)
APIView 类下的self.dispatch
#分发 执行视图 # Get the appropriate handler method if request.method.lower() in self.http_method_names: # self = Publish,反射类中的get方法如果有我就封装到handler里面,如果你没有定义方法我我也就返回一个错误信息 handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed # 也就是说这个地方要么就是调用我Publish的get方法和post方法,要不就抛错误信息 response = handler(request, *args, **kwargs)
return self.response
6.认证频率组件
import time # 自定义限制 VISIT_RECORD = {} class VisitRateThrottle(object): def __init__(self): self.history = None def allow_request(self, request, view): """ 自定义频率限制60秒内只能访问三次 """ # 获取用户IP ip = request.META.get("REMOTE_ADDR") # 获取当前时间戳 timestamp = time.time() # 如果当前访问ip没有在列表中 我就新建一个IP访问记录 if ip not in VISIT_RECORD: VISIT_RECORD[ip] = [timestamp, ] # 可以通过验证 return True # 如果列表中有值,我就取当当前ip地址 赋值给变量 history = VISIT_RECORD[ip] self.history = history # 在列表头部 插入一个时间戳 history.insert(0, timestamp) # 如果列表有值,最先插入的值小于 当前值-60 ,tiemstamp是当前时间是在增加的 while history and history[-1] < timestamp - 60: # pop 取出 最后一个条件成立的值 history.pop() # 列表中的时间戳 大于3 就返回falsse,否则通过 if len(history) > 3: return False else: return True def wait(self): # 返回给前端还剩多少时间可以访问 timestamp = time.time() # 求出还剩多少时间可以访问 return 60 - (timestamp - self.history[-1])
7.解析器 和渲染器
from rest_framework.parsers import JSONParser,FormParser,MultiPartParser,FileUploadParser
parser_classes = [JSONParser,FormParser]
8,解析器(路由控制)
针对:
re_path(r'^authors/$', views.AuthorModelView.as_view({"get":"list","post":"create"}),name="author"),
re_path(r'^author/(?P<pk>d+)/$', views.AuthorModelView.as_view({"get":"retrieve","put":"update","delete":"destroy"}),name="detailauthor"),
class AuthorModelView(viewsets.ModelViewSet):
queryset = Author.objects.all()
serializer_class = AuthorModelSerializers