Django之restframework2视图三部曲

Stella981
• 阅读 530

视图三部曲

下面我来来看restframework是如何将冗余的代码一步步的进行封装.

这里主要用到的是多继承

第一步mixin类编写视图

AuthorModelSerializer:

class AuthorModelSerializer(serializers.ModelSerializer):
    class Meta:
        model=models.Author
        fields='__all__'

from rest_framework import mixins,generics
class Authors(mixins.ListModelMixin,mixins.CreateModelMixin,generics.GenericAPIView):
    queryset = models.Author.objects.all()
    serializer_class = AuthorModelSerializer

    def get(self,request,*args,**kwargs):
        return self.list(request,*args,**kwargs)

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

class AuthorsDetailView(mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,generics.GenericAPIView):
    queryset = models.Author.objects.all()
    serializer_class = AuthorModelSerializer
    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.delete(request,*args,**kwargs)

第二部使用通用的基于类的视图

from rest_framework import generics

class Authors(generics.ListCreateAPIView):
    queryset = models.Author.objects.all()
    serializer_class = AuthorModelSerializer


class AuthorsDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = models.Author.objects.all()
    serializer_class = AuthorModelSerialize


# class ListCreateAPIView(mixins.ListModelMixin,
#                         mixins.CreateModelMixin,
#                         GenericAPIView):
# class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,
#                                    mixins.UpdateModelMixin,
#                                    mixins.DestroyModelMixin,
#                                    GenericAPIView):

通过使用mixin类,我们使用更少的代码重写了这些视图,但我们还可以再进一步。REST框架提供了一组已经混合好(mixed-in)的通用视图,我们可以使用它来简化我们的views.py模块。

到这里是第二部,但是我们还是需要实例化两个类来对应两个url,为什么要实例两个类,因为每个类都有get方法,

如果不写两个类,怎么知道走哪个get方法?

第三部viewsets.ModelViewSet

url部分

path('authors/', views.AuthorModelView.as_view({'get':'list','post':'create'}),name='authors'),
re_path(r'^authors/(?P<pk>\d+)/$', views.AuthorModelView.as_view({'get':'retrieve',
                                                                   'put':'update',
                                                                    'delete':'destroy'}),name='authors_detail'),

##############流程########
from rest_framework import viewsets
class AuthorModelView(viewsets.ModelViewSet):
ModelViewSet--->GenericViewSet--->ViewSetMixin----在这个类下执行了as_view
for method, action in actions.items():
  #as_view后面的参数倍循环后得到了请求key,相对应的方法values
    handler = getattr(self, action) # handler -->getattr(self,list) self--->自己写的类AuthorModelView
    setattr(self, method, handler)   #setattr(self,get,self.list) self.get---->执行self.list

view:

from rest_framework import viewsets
class AuthorModelView(viewsets.ModelViewSet):
    queryset = models.Author.objects.all()
    serializer_class = AuthorModelSerializer

认证组件

局部视图认证:

在app01.authented.py:

from rest_framework.authentication import BaseAuthentication
from app01 import models
from rest_framework.exceptions import AuthenticationFailed

class AuthentiCate(BaseAuthentication):

    def authenticate(self, request):
        token=request.GET.get('token')
        token_obj=models.Token.objects.filter(token=token).first()

        if not token_obj:
            raise AuthenticationFailed('认证失败')
        return token_obj.user.username,token_obj

在views.py:

def get_random_str(user):
    import hashlib,time
    ctime=str(time.time())

    md5=hashlib.md5(bytes(user,encoding="utf8"))
    md5.update(bytes(ctime,encoding="utf8"))

    return md5.hexdigest()

from app01.authented import AuthentiCate

from rest_framework import viewsets
class AuthorModelView(viewsets.ModelViewSet):
    ##*******************###
    authentication_classes = [AuthentiCate]
    ##*******************###
    queryset = models.Author.objects.all()
    serializer_class = AuthorModelSerializer


class LoginView(APIView):

    def post(self,request):
        ret={'status_code':1000,'msg':None}
        try:
            username=request.data.get('username')
            pwd=request.data.get('pwd')

            user=models.User.objects.filter(username=username,pwd=pwd).first()
            if user:
                radom_str=get_random_str(user.username)
                models.Token.objects.update_or_create(user=user,defaults={'token':radom_str})
                ret['token']=radom_str
            else:
                ret['status_code']=1001
                ret['msg']='用户名密码错误'
        except Exception as e:
            res["code"] = 1002
            res["msg"] = e

        return Response(data=ret)

全局视图认证组件:

在settings的配置:

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.authented.AuthentiCate",]
}

权限组件

局部权限组件:

在app01.service.permissions.py中:

from rest_framework.permissions import BasePermission
class SVIPPermission(BasePermission):
    message="SVIP才能访问!"
    def has_permission(self, request, view):
        if request.user.user_type==3:
            return True
        return False

views:

from app01.service.permissions import *

class BookViewSet(generics.ListCreateAPIView):
    permission_classes = [SVIPPermission,]
    queryset = Book.objects.all()
    serializer_class = BookSerializers

全局视图权限

settings.py配置如下:

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
    "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",]
}

如果想添加白名单,在该类下加上permission_classes =[ ]源码找的时候就会先找这里

throttle(访问频率)组件

局部视图throttle:

在app01.service.throttles.py中:

from rest_framework.throttling import BaseThrottle

VISIT_RECORD={}
class VisitThrottle(BaseThrottle):

    def __init__(self):
        self.history=None

    def allow_request(self,request,view):
        remote_addr = request.META.get('REMOTE_ADDR')
        print(remote_addr)
        import time
        ctime=time.time()

        if remote_addr not in VISIT_RECORD:
            VISIT_RECORD[remote_addr]=[ctime,]
            return True

        history=VISIT_RECORD.get(remote_addr)
        self.history=history

        while history and history[-1]<ctime-60:
            history.pop()

        if len(history)<3:
            history.insert(0,ctime)
            return True
        else:
            return False

    def wait(self):
        import time
        ctime=time.time()
        return 60-(ctime-self.history[-1])

在views.py中:

from app01.service.throttles import *

class BookViewSet(generics.ListCreateAPIView):
    throttle_classes = [VisitThrottle,]
    queryset = Book.objects.all()
    serializer_class = BookSerializers

全局视图的throttle

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
    "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
    "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",]
}

内置的throttle类

class VisitThrottle(SimpleRateThrottle):

    scope="visit_rate"
    def get_cache_key(self, request, view):

        return self.get_ident(request)

settings.py设置:

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
    "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
    "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",],
    "DEFAULT_THROTTLE_RATES":{
        "visit_rate":"5/m",
    }
}

解析器

from rest_framework.parsers import JSONParser,FormParser
class PublishViewSet(generics.ListCreateAPIView):
########################
    parser_classes = [FormParser,JSONParser]
############################
    queryset = Publish.objects.all()
    serializer_class = PublshSerializers
    def post(self, request, *args, **kwargs):
        print("request.data",request.data)
        return self.create(request, *args, **kwargs)

全局:

REST_FRAMEWORK={
    "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
    "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",],
    "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",],
    "DEFAULT_THROTTLE_RATES":{
        "visit_rate":"5/m",
    },
    "DEFAULT_PARSER_CLASSES":['rest_framework.parsers.FormParser',]
}

URL的编写

from django.conf.urls import url, include
from rest_framework import routers
from tutorial.quickstart import views

router = routers.DefaultRouter()
router.register(r'authors', views.AuthorsViewSet)


urlpatterns = [
    url(r'^', include(router.urls)),

只要注册了router.register,就会有相对应的

path('authors/',views.AuthorModelView.as_view({'get':'list','post':'create'}),name='authors'),
re_path(r'^authors/(?P<pk>\d+)/$',views.AuthorModelView.as_view({'get':'retrieve','put':'update','delete':'destroy'}),name='authors_detail'),

并且还相应的增加了其他两条restframework的测试url

分页

分页之自定义:

第一版:

from rest_framework.pagination import PageNumberPagination
class Mypagination(PageNumberPagination):
        page_size = 1
        page_query_param = 'page'
        page_size_query_param = "size"
        max_page_size = 5
    
class BookView(APIView):
    # authentication_classes = [TokenAuth,] # [TokenAuth(),]
    # permission_classes = []
    # throttle_classes = []

    def get(self,request):
        book_list=Book.objects.all()

        # 分页

        pnp=Mypagination()
        books_page=pnp.paginate_queryset(book_list,request,self)

        bs=BookModelSerializers(books_page,many=True,context={'request': request})
        return Response(bs.data)

分页之最终版:

from rest_framework.pagination import PageNumberPagination
class Mypagination(PageNumberPagination):
        page_size = 1
        page_query_param = 'page'
        page_size_query_param = "size"
        max_page_size = 5

from rest_framework import viewsets
class AuthorModelView(viewsets.ModelViewSet):
    queryset = models.Author.objects.all()
    serializer_class = AuthorModelSerializer
    pagination_class = Mypagination

偏移分页

from rest_framework.pagination import LimitOffsetPagination

版本的设置

1.设置settings:

REST_FRAMEWORK={
 'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning',#路由配置版本
    'DEFAULT_VERSION':'v1', #默认的版本
    'ALLOWED_VERSIONS':['v1','v2'], #允许的版本
    'VERSION_PARAM':'version', # 版本参数

2.设置路由:
分发的时候设置:

urlpatterns = [
    path('admin/', admin.site.urls),
    re_path(r'^api/(?P<version>\w+)/', include('api.urls')),
]

3.获取版本:

request.version #获取版本

 跨域请求CORS

CORS:
解决跨域的时候是加上特殊的响应头
jsonp跨域只能是get请求,
cors可以发送post和get请求.

配置中间件
from django.utils.deprecation import MiddlewareMixin
class CORSMiddleware(MiddlewareMixin):
    def process_response(self,request,response):
        #添加响应头
        # 允许你的域名来获取我的数据
        # 允许所有的域名来获取数据
        response['Access-Control-Allow-Origin']='*'

        # 允许你携带Content-Type请求头 如果要多的用逗号,隔开
        response['Access-Control-Allow-Headers']='Content-Type'

        # 允许你发送DELETE,和PUT
        response['Access-Control-Allow-Methods']='DELETE,PUT'

        return response
#setting里配置
MIDDLEWARE = [
'api.cors.CORSMiddleware',
]

restful规范 猛击!

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
Java获得今日零时零分零秒的时间(Date型)
publicDatezeroTime()throwsParseException{    DatetimenewDate();    SimpleDateFormatsimpnewSimpleDateFormat("yyyyMMdd00:00:00");    SimpleDateFormatsimp2newS
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这