欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

rest-framework框架的基本组件

程序员文章站 2022-05-02 16:33:25
序列化 创建一个序列化类 简单使用 开发我们的Web API的第一件事是为我们的Web API提供一种将代码片段实例序列化和反序列化为诸如json之类的表示形式的方式。我们可以通过声明与Django forms非常相似的序列化器(serializers)来实现。 models部分: views部分: ......

序列化

创建一个序列化类

简单使用

开发我们的web api的第一件事是为我们的web api提供一种将代码片段实例序列化和反序列化为诸如json之类的表示形式的方式。我们可以通过声明与django forms非常相似的序列化器(serializers)来实现。

models部分:

rest-framework框架的基本组件
from django.db import models

# create your models here.


class book(models.model):
    title=models.charfield(max_length=32)
    price=models.integerfield()
    pub_date=models.datefield()
    publish=models.foreignkey("publish")
    authors=models.manytomanyfield("author")
    def __str__(self):
        return self.title

class publish(models.model):
    name=models.charfield(max_length=32)
    email=models.emailfield()
    def __str__(self):
        return self.name

class author(models.model):
    name=models.charfield(max_length=32)
    age=models.integerfield()
    def __str__(self):
        return self.name
rest-framework框架的基本组件

views部分:

rest-framework框架的基本组件
from rest_framework.views import apiview
from rest_framework.response import response
from .models import *
from django.shortcuts import httpresponse
from django.core import serializers


from rest_framework import serializers

class bookserializers(serializers.serializer):
    title=serializers.charfield(max_length=32)
    price=serializers.integerfield()
    pub_date=serializers.datefield()
    publish=serializers.charfield(source="publish.name")
    #authors=serializers.charfield(source="authors.all")
    authors=serializers.serializermethodfield()
    def get_authors(self,obj):
        temp=[]
        for author in obj.authors.all():
            temp.append(author.name)
        return temp


class bookviewset(apiview):

    def get(self,request,*args,**kwargs):
        book_list=book.objects.all()
        # 序列化方式1:
        # from django.forms.models import model_to_dict
        # import json
        # data=[]
        # for obj in book_list:
        #     data.append(model_to_dict(obj))
        # print(data)
        # return httpresponse("ok")

        # 序列化方式2:
        # data=serializers.serialize("json",book_list)
        # return httpresponse(data)

        # 序列化方式3:
        bs=bookserializers(book_list,many=true)
        return response(bs.data)
rest-framework框架的基本组件

modelserializer

class bookserializers(serializers.modelserializer):
      class meta:
          model=book
          fields="__all__"
          depth=1

提交post请求

rest-framework框架的基本组件
  def post(self,request,*args,**kwargs):
       
        bs=bookserializers(data=request.data,many=false)
        if bs.is_valid():
            # print(bs.validated_data)
            bs.save()
            return response(bs.data)
        else:
            return httpresponse(bs.errors)
rest-framework框架的基本组件

重写save中的create方法

rest-framework框架的基本组件
class bookserializers(serializers.modelserializer):

      class meta:
          model=book
          fields="__all__"
          # exclude = ['authors',]
          # depth=1

      def create(self, validated_data):
        
          authors = validated_data.pop('authors')
          obj = book.objects.create(**validated_data)
          obj.authors.add(*authors)
          return obj
rest-framework框架的基本组件

 单条数据的get和put请求

rest-framework框架的基本组件
class bookdetailviewset(apiview):

    def get(self,request,pk):
        book_obj=book.objects.filter(pk=pk).first()
        bs=bookserializers(book_obj)
        return response(bs.data)

    def put(self,request,pk):
        book_obj=book.objects.filter(pk=pk).first()
        bs=bookserializers(book_obj,data=request.data)
        if bs.is_valid():
            bs.save()
            return response(bs.data)
        else:
            return httpresponse(bs.errors)
rest-framework框架的基本组件

超链接api:hyperlinked

rest-framework框架的基本组件
class bookserializers(serializers.modelserializer):
      publish= serializers.hyperlinkedidentityfield(
view_name='publish_detail',
lookup_field="publish_id",
lookup_url_kwarg="pk") class meta: model=book fields="__all__" #depth=1
rest-framework框架的基本组件

urls部分:

1
2
3
4
5
6
urlpatterns = [
    url(r'^books/$', views.bookviewset.as_view(),name="book_list"),
    url(r'^books/(?p<pk>\d+)$', views.bookdetailviewset.as_view(),name="book_detail"),
    url(r'^publishers/$', views.publishviewset.as_view(),name="publish_list"),
    url(r'^publishers/(?p<pk>\d+)$', views.publishdetailviewset.as_view(),name="publish_detail"),
]

视图三部曲

使用混合(mixins)

上一节的视图部分:

rest-framework框架的基本组件
from rest_framework.views import apiview
from rest_framework.response import response
from .models import *
from django.shortcuts import httpresponse
from django.core import serializers


from rest_framework import serializers


class bookserializers(serializers.modelserializer):
      class meta:
          model=book
          fields="__all__"
          #depth=1


class publshserializers(serializers.modelserializer):

      class meta:
          model=publish
          fields="__all__"
          depth=1


class bookviewset(apiview):

    def get(self,request,*args,**kwargs):
        book_list=book.objects.all()
        bs=bookserializers(book_list,many=true,context={'request': request})
        return response(bs.data)


    def post(self,request,*args,**kwargs):
        print(request.data)
        bs=bookserializers(data=request.data,many=false)
        if bs.is_valid():
            print(bs.validated_data)
            bs.save()
            return response(bs.data)
        else:
            return httpresponse(bs.errors)


class bookdetailviewset(apiview):

    def get(self,request,pk):
        book_obj=book.objects.filter(pk=pk).first()
        bs=bookserializers(book_obj,context={'request': request})
        return response(bs.data)

    def put(self,request,pk):
        book_obj=book.objects.filter(pk=pk).first()
        bs=bookserializers(book_obj,data=request.data,context={'request': request})
        if bs.is_valid():
            bs.save()
            return response(bs.data)
        else:
            return httpresponse(bs.errors)


class publishviewset(apiview):

    def get(self,request,*args,**kwargs):
        publish_list=publish.objects.all()
        bs=publshserializers(publish_list,many=true,context={'request': request})
        return response(bs.data)


    def post(self,request,*args,**kwargs):

        bs=publshserializers(data=request.data,many=false)
        if bs.is_valid():
            # print(bs.validated_data)
            bs.save()
            return response(bs.data)
        else:
            return httpresponse(bs.errors)


class publishdetailviewset(apiview):

    def get(self,request,pk):

        publish_obj=publish.objects.filter(pk=pk).first()
        bs=publshserializers(publish_obj,context={'request': request})
        return response(bs.data)

    def put(self,request,pk):
        publish_obj=publish.objects.filter(pk=pk).first()
        bs=publshserializers(publish_obj,data=request.data,context={'request': request})
        if bs.is_valid():
            bs.save()
            return response(bs.data)
        else:
            return httpresponse(bs.errors)
rest-framework框架的基本组件

mixin类编写视图

rest-framework框架的基本组件
from rest_framework import mixins
from rest_framework import generics

class bookviewset(mixins.listmodelmixin,
                  mixins.createmodelmixin,
                  generics.genericapiview):

    queryset = book.objects.all()
    serializer_class = bookserializers

    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 bookdetailviewset(mixins.retrievemodelmixin,
                    mixins.updatemodelmixin,
                    mixins.destroymodelmixin,
                    generics.genericapiview):
    queryset = book.objects.all()
    serializer_class = bookserializers

    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.destroy(request, *args, **kwargs)
rest-framework框架的基本组件

使用通用的基于类的视图

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

rest-framework框架的基本组件
from rest_framework import mixins
from rest_framework import generics

class bookviewset(generics.listcreateapiview):

    queryset = book.objects.all()
    serializer_class = bookserializers

class bookdetailviewset(generics.retrieveupdatedestroyapiview):
    queryset = book.objects.all()
    serializer_class = bookserializers

class publishviewset(generics.listcreateapiview):

    queryset = publish.objects.all()
    serializer_class = publshserializers

class publishdetailviewset(generics.retrieveupdatedestroyapiview):
    queryset = publish.objects.all()
    serializer_class = publshserializers
rest-framework框架的基本组件

viewsets.modelviewset

urls.py:

rest-framework框架的基本组件
    url(r'^books/$', views.bookviewset.as_view({"get":"list","post":"create"}),name="book_list"),
    url(r'^books/(?p<pk>\d+)$', views.bookviewset.as_view({
                'get': 'retrieve',
                'put': 'update',
                'patch': 'partial_update',
                'delete': 'destroy'
            }),name="book_detail"),
rest-framework框架的基本组件

views.py:

class bookviewset(viewsets.modelviewset):
    queryset = book.objects.all()
    serializer_class = bookserializers

认证与权限组件

认证组件

局部视图认证

在app01.service.auth.py:

rest-framework框架的基本组件
class authentication(baseauthentication):

    def authenticate(self,request):
        token=request._request.get.get("token")
        token_obj=usertoken.objects.filter(token=token).first()
        if not token_obj:
            raise exceptions.authenticationfailed("验证失败!")
        return (token_obj.user,token_obj)
rest-framework框架的基本组件

在views.py:

rest-framework框架的基本组件
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.service.auth import *

from django.http import jsonresponse
class loginviewset(apiview):
    authentication_classes = [authentication,]
    def post(self,request,*args,**kwargs):
        res={"code":1000,"msg":none}
        try:
            user=request._request.post.get("user")
            pwd=request._request.post.get("pwd")
            user_obj=userinfo.objects.filter(user=user,pwd=pwd).first()
            print(user,pwd,user_obj)
            if not user_obj:
                res["code"]=1001
                res["msg"]="用户名或者密码错误"
            else:
                token=get_random_str(user)
                usertoken.objects.update_or_create(user=user_obj,defaults={"token":token})
                res["token"]=token

        except exception as e:
            res["code"]=1002
            res["msg"]=e

        return jsonresponse(res,json_dumps_params={"ensure_ascii":false})
rest-framework框架的基本组件

全局视图认证组件

settings.py配置如下:

1
2
3
rest_framework={
    "default_authentication_classes":["app01.service.auth.authentication",]
}

权限组件

局部视图权限

在app01.service.permissions.py中:

rest-framework框架的基本组件
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
rest-framework框架的基本组件

在views.py:

from app01.service.permissions import *

class bookviewset(generics.listcreateapiview):
    permission_classes = [svippermission,]
    queryset = book.objects.all()
    serializer_class = bookserializers

全局视图权限

settings.py配置如下:

1
2
3
4
rest_framework={
    "default_authentication_classes":["app01.service.auth.authentication",],
    "default_permission_classes":["app01.service.permissions.svippermission",]
}

throttle(访问频率)组件

局部视图throttle

在app01.service.throttles.py中:

rest-framework框架的基本组件
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])
rest-framework框架的基本组件

在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类

在app01.service.throttles.py修改为:

class visitthrottle(simpleratethrottle):

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

        return self.get_ident(request)

settings.py设置:

rest-framework框架的基本组件
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",
    }
}
rest-framework框架的基本组件

解析器

request类

django的request类和rest-framework的request类的源码解析

局部视图

rest-framework框架的基本组件
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框架的基本组件

全局视图

rest-framework框架的基本组件
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',]
}
rest-framework框架的基本组件
 

分页

简单分页

rest-framework框架的基本组件
from rest_framework.pagination import pagenumberpagination,limitoffsetpagination

class pnpagination(pagenumberpagination):
        page_size = 1
        page_query_param = 'page'
        page_size_query_param = "size"
        max_page_size = 5

class bookviewset(viewsets.modelviewset):

    queryset = book.objects.all()
    serializer_class = bookserializers
    def list(self,request,*args,**kwargs):

        book_list=book.objects.all()
        pp=limitoffsetpagination()
        pager_books=pp.paginate_queryset(queryset=book_list,request=request,view=self)
        print(pager_books)
        bs=bookserializers(pager_books,many=true)

        #return response(bs.data)
        return pp.get_paginated_response(bs.data)
rest-framework框架的基本组件

偏移分页

from rest_framework.pagination import limitoffsetpagination