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部分:
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
views部分:
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)
modelserializer
class bookserializers(serializers.modelserializer): class meta: model=book fields="__all__" depth=1
提交post请求
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)
重写save中的create方法
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
单条数据的get和put请求
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)
超链接api:hyperlinked
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
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)
上一节的视图部分:
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)
mixin类编写视图
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)
使用通用的基于类的视图
通过使用mixin类,我们使用更少的代码重写了这些视图,但我们还可以再进一步。rest框架提供了一组已经混合好(mixed-in)的通用视图,我们可以使用它来简化我们的views.py
模块。
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
viewsets.modelviewset
urls.py:
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"),
views.py:
class bookviewset(viewsets.modelviewset): queryset = book.objects.all() serializer_class = bookserializers
认证与权限组件
认证组件
局部视图认证
在app01.service.auth.py:
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)
在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.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})
全局视图认证组件
settings.py配置如下:
1
2
3
|
rest_framework = {
"default_authentication_classes" :[ "app01.service.auth.authentication" ,]
} |
权限组件
局部视图权限
在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.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中:
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类
在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={ "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", } }
解析器
request类
django的request类和rest-framework的request类的源码解析
局部视图
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',] }
分页
简单分页
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)
偏移分页
from rest_framework.pagination import limitoffsetpagination