文章目录
- restful协议
- restframework基于restful协议开发
- restframework视图
- token拓展
- 认证、权限、频率
- 分页器
- 解析器
- 根据url指定渲染器
- 返回json数据
- 表格
- form表单
- API+JSON
- 渲染拓展
restful协议
--- 一切皆是资源,操作只是请求方式
---book表增删改查
/books/ books
/books/add/ addbook
/books/(\d+)/change/ changebook
/books/(\d+)/delete/ delbook
---book表增删改查
/books/ ----get books ---- 返回当前所有数据
/books/ ----post books ---- 返回提交数据
/books/(\d+)----get bookdetail ---- 返回当前查看的单条数据
/books/(\d+)----put bookdetail ---- 返回更新数据
/books/(\d+)----delete bookdetail ---- 返回空数据
# 示例
from django.views import View
class Books(View):
def get(self,request):
pass # 查看所有书籍
def post(self,request):
pass # 添加书籍
class BooksDetail(View):
def get(self,request,id):
pass # 查看具体书籍
def put(self,request,id):
pass # 更新某本书籍
def delete(self,request,id):
pass # 删除某本书籍
restframework基于restful协议开发
pip install django
pip install restframework
序列化类
# 方式1:
publish_list=list(Publish.objects.all().values("name","email"))
return HttpResponse(json.dumps(publish_list))
# 方式2:
from django.forms.models import model_to_dict
publish_list = Publish.objects.all()
temp=[]
for obj in publish_list:
temp.append(model_to_dict(obj))
return HttpResponse(json.dumps(temp))
# 方式3:
from django.core import serializers
publish_list = Publish.objects.all()
ret = serializers.serialize("json",publish_list)
return HttpResponse(ret)
# 方法4
from rest_framework import serializers
# 继承类serializers.Serializer,为queryset,model对象做序列化
class PublishSerializers(serializers.Serializer):
name = serializers.CharField()
email = serializers.CharField()
from rest_framework.response import Response
publish_list = Publish.objects.all()
ps = PublishModelSerializers(publish_list, many=True)
return Response(ps.data)
# 多对多restframe序列化
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")# 跨表显示name
#authors=serializers.CharField(source="authors.all")
authors = serializers.SerializerMethodField()
def get_authors(self,obj):
temp=[]
for obj in obj.authors.all():
temp.append(obj.name)
return temp
# 相当于下面
'''
序列化BookSerializers(book_list,many=True)过程:
temp=[]
for obj in book_list:
temp.append({
"title":obj.title,
"price":obj.price,
"pub_date":obj.pub_date,
#"publish":str(obj.publish), # 表Publish 定义的返回字段的值
"publish":str(obj.publish.name), # source="publish.name"
#"authors":obj.authors.all,
"authors": get_authors(obj)
})
'''
# 方法5 更简单的默认restframe序列化
from rest_framework import serializers
class BookModelSerializers(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
# 案例
# 路由函数
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^publishes/$', views.PublishView.as_view(),name="publish"),
url(r'^publishes/(?P\d+)/$', views.PublishDetailView.as_view(),name="detailpublish"),
url(r'^books/$', views.BookView.as_view(),name="books"),
url(r'^books/(\d+)/$', views.BookDetailView.as_view(),name="detailbook"),
]
# serializer.py
from rest_framework import serializers
# 继承ModelSerializer,可以实现序列化、数据校验、存储功能
class BookModelSerializers(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
# 自定义字段,显示链接
publish=serializers.HyperlinkedIdentityField(
# 显示链接的路由名
view_name="detailpublish",
# 获取当前对象对应的字段值
lookup_field="publish_id",
# 该值放在组pk的位置
lookup_url_kwarg="pk"
)
# 视图函数
from rest_framework.response import Response # Response可以返回格式化对象
from app01.serilizer import *
class BookView(APIView):
# get返回所有对象
def get(self,request):
book_list=Book.objects.all()
# 自定义字段,显示连接,序列化时必须加上context={'request': request}
bs=BookModelSerializers(book_list,many=True,context={'request': request})
return Response(bs.data)
# post返回发送的对象
def post(self,request):
# post请求的数据
bs=BookModelSerializers(data=request.data)
# 校验数据
if bs.is_valid():
print(bs.validated_data)
bs.save()# create方法存储数据到数据库
return Response(bs.data)
else:
return Response(bs.errors)
class BookDetailView(APIView):
def get(self,request,id):
book=Book.objects.filter(pk=id).first()
bs=BookModelSerializers(book,context={'request': request})
return Response(bs.data)
# put返回编辑对象
def put(self,request,id):
book=Book.objects.filter(pk=id).first()
bs=BookModelSerializers(book,data=request.data)
if bs.is_valid():
bs.save()
return Response(bs.data)
else:
return Response(bs.errors)
# delete返回None
def delete(self,request,id):
Book.objects.filter(pk=id).delete()
return Response()
request拓展
request.POST 为url携带数据或form携带数据
request.body 携带数据的二进制模式,可以是urlencode、form、json
rest_framework.views的request特殊取值
from rest_framework.views import APIView
class PublishView(APIView):
def get(self,request):
# 序列组件
class PublishSerializers(serializers.Serializer):
name = serializers.CharField()
email = serializers.CharField()
publish_list = Publish.objects.all()
ps = PublishSerializers(publish_list, many=True)
return Response(ps.data)
def post(self,request):
# APIView新的request支持的操作
print("request.data",request.data)# 只能接受post携带数据,json数据
print("request.GET",request.GET)# GET携带的数据,同下
print("request.GET",request._request.GET)# GET携带的数据
print("request.data type",type(request.data))
restframework视图
# 基于功能的视图
from rest_framework import mixins
from rest_framework import generics
# 继承List、Create、APIView
class AuthorView(mixins.ListModelMixin,mixins.CreateModelMixin,generics.GenericAPIView):
# 下面2个为固定参数必须写
queryset=Author.objects.all() # 所有对象
serializer_class =AuthorModelSerializers # 序列化的类方法
def get(self,request, *args, **kwargs):
# self.list()方法即,序列化对象,返回序列化后的对象
return self.list(request, *args, **kwargs)
def post(self,request, *args, **kwargs):
return self.create(request, *args, **kwargs)
# 继承Retrieve、Destroy、Update、APIView
class AuthorDetailView(mixins.RetrieveModelMixin,mixins.DestroyModelMixin,mixins.UpdateModelMixin,generics.GenericAPIView):
queryset = Author.objects.all()
serializer_class = AuthorModelSerializers
def get(self,request,*args, **kwargs):
return self.retrieve(request,*args, **kwargs)
def delete(self,request,*args, **kwargs):
return self.destroy(request,*args, **kwargs)
def put(self,request,*args, **kwargs):
return self.retrieve(request,*args, **kwargs)
# 基于通用类
from rest_framework import mixins
from rest_framework import generics
# 在ListCreateAPIView里面有get对应list方法,post对应create方法
class AuthorView(generics.ListCreateAPIView):
queryset=Author.objects.all()
serializer_class =AuthorModelSerializers
class AuthorDetailView(generics.RetrieveUpdateDestroyAPIView):
queryset = Author.objects.all()
serializer_class = AuthorModelSerializers
# 基于视图集
# 路由需要改
url(r'^authors/$', views.AuthorModelView.as_view({"get":"list","post":"create"}),name="author"),
url(r'^authors/(?P\d+)/$', views.AuthorModelView.as_view({"get":"retrieve","put":"update","delete":"destroy"}),name="detailauthor"),
# 视图函数
from rest_framework import viewsets
from app01.utils import TokenAuth
class AuthorModelView(viewsets.ModelViewSet):
queryset = Author.objects.all()
serializer_class = AuthorModelSerializers
token拓展
def get_random_str(user):
import hashlib,time
ctime=str(time.time())
# 密钥
md5=hashlib.md5(bytes(user,encoding="utf8"))
# md5加密ctime
md5.update(bytes(ctime,encoding="utf8"))
return md5.hexdigest()
from .models import User
class LoginView(APIView):
def post(self,request):
name=request.data.get("name")
pwd=request.data.get("pwd")
user=User.objects.filter(name=name,pwd=pwd).first()
res = {"state_code": 1000, "msg": None}
if user:
# 获取token
random_str=get_random_str(user.name)
token=Token.objects.update_or_create(user=user,defaults={"token":random_str})
res["token"]=random_str
else:
res["state_code"]=1001 #错误状态码
res["msg"] = "用户名或者密码错误"
import json
return Response(json.dumps(res,ensure_ascii=False))
认证、权限、频率
from rest_framework import exceptions
from rest_framework.authentication import BaseAuthentication
from rest_framework.permissions import BasePermission
from .models import *
class TokenAuth(BaseAuthentication):
def authenticate(self,request):
token = request.data.get("token")
token_obj = Token.objects.filter(token=token).first()
if not token_obj:
raise exceptions.AuthenticationFailed("验证失败123!")
else:
return token_obj.user.name,token_obj.token
class MyPermission(BasePermission):
message = '无权访问'
def has_permission(self,request,view): # 此时的self是view视图对象
if request.user:
return True #如果不是匿名用户就说明有权限
return False #否则无权限
class AdminPermission(BasePermission):
message = '无权访问'
def has_permission(self, request, view): # 此时的self是view视图对象
if request.user=='haiyun':
return True # 返回True表示有权限
return False #返回False表示无权限
# 自定义频率限制
VISIT_RECORD = {}
class MyThrottle(object):
def __init__(self):
self.history = None
def allow_request(self, request, view):
"""
自定义频率限制60秒内只能访问三次
"""
# 获取用户IP
ip = request.META.get("REMOTE_ADDR")
timestamp = time.time()
if ip not in VISIT_RECORD:
VISIT_RECORD[ip] = [timestamp, ]
return True
history = VISIT_RECORD[ip]
self.history = history
history.insert(0, timestamp)
# 超过60秒的登录记录删除
while history and history[-1] < timestamp - 60:
history.pop()
# 判断是否超过3次访问记录
if len(history) > 3:
return False
else:
return True
def wait(self):
"""
限制时间还剩多少
"""
timestamp = time.time()
return 60 - (timestamp - self.history[-1])
class AuthorModelView(viewsets.ModelViewSet):
# 当前试图使用
authentication_classes = [TokenAuth,]
permission_classes = [MyPermission,AdminPermission]
throttle_classes = [MyThrottle, ]
queryset = Author.objects.all()
serializer_class = AuthorModelSerializers
全局认证
修改settings,将自己编写的认证类
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.TokenAuth",],
"DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.MyAuth", ],
"DEFAULT_PERMISSION_CLASSES": ["app01.utils.MyPermission", ],
"DEFAULT_THROTTLE_CLASSES": ["app01.utils.MyThrottle", ]
}
分页器
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination
class MyPageNumberPagination(PageNumberPagination):
# 每页显示数据几条
page_size = 2
# 数据关键字
page_query_param = 'page'
# 临时修改每页显示数据条数的关键字
page_size_query_param="size"
# 临时修改每页显示数据的最大值
max_page_size=10
class MyLimitOffsetPagination(LimitOffsetPagination):
# 每页显示数据条数
default_limit=3
class BookView(APIView):
parser_classes = [JSONParser,FormParser]
def get(self,request):
book_list=Book.objects.all()
# 分页
pnp=MyPageNumberPagination() ?page=2
# page为第几页
# pnp=MyLimitOffsetPagination() ?offset=2&limit=2
# offset为跳过几个数据,limit为显示几条数据
# 固定调用方式,返回值为queryset对象
books_page=pnp.paginate_queryset(book_list,request,self)
bs=BookModelSerializers(books_page,many=True)
return Response(bs.data)
解析器
# 四种解析器
from rest_framework.parsers import JSONParser,FormParser,MultiPartParser,FileUploadParser
class BookView(APIView):
# 加上parser_classes便可指定解析器,解析指定类型数据
parser_classes = [JSONParser,FormParser]
def get(self,request):
pass
# 分页
pnp=MyLimitOffsetPagination()
books_page=pnp.paginate_queryset(book_list,request,self)
bs=BookModelSerializers(books_page,many=True,context={'request': request})
return Response(bs.data)
根据url指定渲染器
返回json数据
http://127.0.0.1:8000/test/?format=json
http://127.0.0.1:8000/test.json
http://127.0.0.1:8000/test/
# 路由函数
from django.conf.urls import url, include
from web import views
urlpatterns = [
url(r'^test/$', views.TestView.as_view()),
url(r'^test\.(?P[a-z0-9]+)', views.TestView.as_view()),
]
# 视图函数
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from rest_framework.renderers import JSONRenderer
from .. import models
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class TestView(APIView):
# 渲染器JSON
renderer_classes = [JSONRenderer, ]
def get(self, request, *args, **kwargs):
user_list = models.UserInfo.objects.all()
ser = TestSerializer(instance=user_list, many=True)
return Response(ser.data)
表格
http://127.0.0.1:8000/test/?format=admin
http://127.0.0.1:8000/test.admin
http://127.0.0.1:8000/test/
# 路由函数
from django.conf.urls import url, include
from web import views
urlpatterns = [
url(r'^test/$', views.TestView.as_view()),
url(r'^test\.(?P[a-z0-9]+)', views.TestView.as_view()),
]
# 视图函数
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from rest_framework.renderers import AdminRenderer
from .. import models
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class TestView(APIView):
# 表格渲染器
renderer_classes = [AdminRenderer, ]
def get(self, request, *args, **kwargs):
user_list = models.UserInfo.objects.all()
ser = TestSerializer(instance=user_list, many=True)
return Response(ser.data)
form表单
http://127.0.0.1:8000/test/?format=form
http://127.0.0.1:8000/test.form
http://127.0.0.1:8000/test/
# 路由函数
from django.conf.urls import url, include
from web import views
urlpatterns = [
url(r'^test/$', views.TestView.as_view()),
url(r'^test\.(?P[a-z0-9]+)', views.TestView.as_view()),
]
# 视图函数
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from rest_framework.renderers import HTMLFormRenderer
from .. import models
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class TestView(APIView):
# 表单渲染器
renderer_classes = [HTMLFormRenderer, ]
def get(self, request, *args, **kwargs):
user_list = models.UserInfo.objects.all().first()
ser = TestSerializer(instance=user_list, many=False)
return Response(ser.data)
API+JSON
http://127.0.0.1:8000/test/?format=api
http://127.0.0.1:8000/test.api
http://127.0.0.1:8000/test/
# 路由函数
from django.conf.urls import url, include
from web import views
urlpatterns = [
url(r'^test/$', views.TestView.as_view()),
url(r'^test\.(?P[a-z0-9]+)', views.TestView.as_view()),
]
# 视图函数
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from rest_framework.renderers import JSONRenderer
from rest_framework.renderers import BrowsableAPIRenderer
from .. import models
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
# 自定义api+json渲染器
class CustomBrowsableAPIRenderer(BrowsableAPIRenderer):
def get_default_renderer(self, view):
return JSONRenderer()
class TestView(APIView):
# 引用自定义渲染器
renderer_classes = [CustomBrowsableAPIRenderer, ]
def get(self, request, *args, **kwargs):
user_list = models.UserInfo.objects.all().first()
ser = TestSerializer(instance=user_list, many=False)
return Response(ser.data, template_name='user_detail.html')
渲染拓展
路由都可改为,即可自动实现
from django.conf.urls import url,include
from rest_framework import routers
from app01 import views
routers=routers.DefaultRouter()
routers.register("authors",views.AuthorModelView)
urlpatterns = [
url(r'', include(routers.urls)),
]