本文的目的是介绍为整个结果集向DjangoRestFramework结果添加额外的数据的详细情况,特别关注实现对一个结果集进行分组和汇总的相关信息。我们将通过专业的研究、有关数据的分析等多种方式,为您
本文的目的是介绍为整个结果集向Django Rest Framework结果添加额外的数据的详细情况,特别关注实现对一个结果集进行分组和汇总的相关信息。我们将通过专业的研究、有关数据的分析等多种方式,为您呈现一个全面的了解为整个结果集向Django Rest Framework结果添加额外的数据的机会,同时也不会遗漏关于1 Django REST Framework 开发 ---- 原生 Django View 热身、Django - rest - framework - 下、django - 插件 django REST framework, 返回序列化的数据、Django Rest Framework的知识。
本文目录一览:- 为整个结果集向Django Rest Framework结果添加额外的数据(实现对一个结果集进行分组和汇总)
- 1 Django REST Framework 开发 ---- 原生 Django View 热身
- Django - rest - framework - 下
- django - 插件 django REST framework, 返回序列化的数据
- Django Rest Framework
为整个结果集向Django Rest Framework结果添加额外的数据(实现对一个结果集进行分组和汇总)
我正在使用Django Rest Framework,并且需要向结果集中添加额外的数据。具体来说,通常在哪里:
{ "count": 45, "next": "http://localhost:8000/foo/bar?page=2", "previous": null, "results": [ {...} ]}
我想添加额外的计数,如下所示:
{ "count": 45, "10_mi_count": 10, "20_mi_count": 30, "30_mi_count": 45, "next": "http://localhost:8000/foo/bar?page=2", "previous": null, "results": [ {...} ]}
在此示例中,额外计数仅是多少个对象的视场距离值小于键中描述的英里数。
我的问题是我不知道扩展和插入此行为的最佳位置在哪里。
理想情况下,无论结果是否分页,我都希望此方法可以工作,无需做任何假设。
我真正要追求的是朝着正确的方向点头(以及为什么这是正确的选择)。
我检查了文档,找不到任何描述如何添加类似内容的内容,但我很乐意在该分数上被证明是错误的。
答案1
小编典典由于您似乎正在使用Rest框架中的ListView之一,因此可以覆盖类中的list()方法并在结果数据上设置新值,如下所示:
def list(self, request, *args, **kwargs): response = super().list(request, args, kwargs) # Add data to response.data Example for your object: response.data[''10_mi_count''] = 10 # Or wherever you get this values from response.data[''20_mi_count''] = 30 response.data[''30_mi_count''] = 45 return response
请注意,您的类必须直接或通过Rest Framework API(http://www.django-rest-framework.org/api-
guide/generic-views#listmodelmixin)的GenericView继承ListModelMixin
。我真的不知道这是否是正确的方法,但这是一个快速解决方案。
希望能帮助到你!
1 Django REST Framework 开发 ---- 原生 Django View 热身
在正式开始 Django REST Framework 学习之前,先用 django.core.serializers 和原生的 Django View 类来实现一次数据的序列化数据。
下面的例子展示了,是如何解决序列化 JSON 数据的,前提:给Products的Model已经创建完
创建 Django 项目,并修改 urls.py 文件:
1 from django.views.generic import TemplateView
2 from product.views import ProductsListView
3
4
5 urlpatterns = [
6 url(r''^admin/'', admin.site.urls),
7 url(r''^products/'', ProductsListView.as_view(), name="product-list"),
8 ]
创建 view.py 文件并写入如下内容:
1 import json
2
3 from django.http import JsonResponse
4 from django.core import serializers
5 from django.views.generic.base import View
6
7 from products.models import Product
8
9
10 class ProductListView(View):
11 def get(self, request):
12 products = Product.objects.all()
13 json_data = serializers.serialize(''json'', products) # 将django model 得到的对象序列化成 json 类型
14 json_data = json.loads(json_data)
15
16 return JsonResponse(json_data, safe=False) # safe = False 因为json_data是 non-dict 类型,不然会报错
注:在打开网页显示数据时需下载chrome jsonview插件
这样一个基本的django 使用json数据类型调取数据的过程就完成了,但是会有以下问题:
- 图片,日期格式支持不够(仅会显示图片相对路径)
- 主键JSON字段之外,使得调用起来会不方便
- 文档需要手动写,缺乏规范性且效率低下
- 输入验证缺失 (类似于表单的认证)
- 等等
Django - rest - framework - 下
一、视图三部曲
https://www.cnblogs.com/wupeiqi/articles/7805382.html
使用混合(mixins)
之前得视图部分
# urls.py
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<pk>\d+)/$'', views.PublishDetailView.as_view(),name="detail_publish"),
url(r"^books/$", views.BookView.as_view(),name="books"),
url(r''^books/(?P<pk>\d+)/$'',views.BookDetailView.as_view(),name="detail_book")
]
------------------------------------------------------
# views.py
from rest_framework.views import APIView, Response
from app01.serializers import *
class PublishView(APIView):
def get(self, request):
publish_list = Publish.objects.all()
ret = PublishModelSerializers(publish_list, many=True)
return Response(ret.data)
def post(self, request):
ps = PublishModelSerializers(data=request.data)
if ps.is_valid():
ps.save()
return Response(ps.data)
else:
return Response(ps.errors)
class PublishDetailView(APIView):
def get(self,request,pk):
publish = Publish.objects.filter(pk=pk).first()
ps = PublishModelSerializers(publish)
return Response(ps.data)
def put(self,request,pk):
publish = Publish.objects.filter(pk=pk).first()
ps = PublishModelSerializers(publish,data=request.data)
if ps.is_valid():
ps.save()
return Response(ps.data)
else:
return Response(ps.errors)
def delete(self,request,pk):
Publish.objects.filter(pk=pk).delete()
return Response()
class BookView(APIView):
def get(self, request):
book_list = Book.objects.all()
ret = BookModelSerializers(book_list, many=True,context={"request":request})
return Response(ret.data)
def post(self, request):
bms = BookModelSerializers(data=request.data, many=False,context={"request":request})
if bms.is_valid():
bms.save()
return Response(bms.data)
else:
return Response(bms.errors)
class BookDetailView(APIView):
def get(self,request,pk):
book = Book.objects.filter(pk=pk).first()
# 序列化
bms = BookModelSerializers(book,context={"request":request})
return Response(bms.data)
def put(self,request,pk):
book = Book.objects.filter(pk=pk).first()
bms = BookModelSerializers(book,data=request.data,context={"request":request})
if bms.is_valid():
bms.save()
return Response(bms.data)
else:
return Response(bms.errors)
def delete(self,reqeust,pk):
Book.objects.filter(pk=pk).delete()
return Response()
---------------------------------------------------
# serializers.py
# -*- coding:utf-8 -*-
from .models import *
from rest_framework import serializers
class PublishModelSerializers(serializers.ModelSerializer):
class Meta:
model = Publish
fields = "__all__"
class BookModelSerializers(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"


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
1. mixin类编写视图
from rest_framework import mixins, generics
mixins.ListModelMixin, mixins.CreateModelMixin,
mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin,
generics.GenericAPIView
url(r''^authors/$'',views.AuthorView.as_view(),name="author"),
url(r''^authors/(?P<pk>\d+)'',views.AuthorDetailView.as_view(),name="detail_author"),
-----------------------------------------
######################### mixin类编写视图 ##############################
from rest_framework import mixins, generics
class AuthorView(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView):
queryset = Author.objects.all()
serializer_class = AuthorModelSerializers
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 AuthorDetailView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin,
generics.GenericAPIView):
queryset = Author.objects.all()
serializer_class = AuthorModelSerializers
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)
------------------------------------------------
class AuthorModelSerializers(serializers.ModelSerializer):
class Meta:
model = Author
fields = "__all__"
2. 使用通用的基于类的视图
from rest_framework import generics
generics.ListCreateAPIView
generics.RetrieveUpdateDestroyAPIView
通过使用mixin类,我们使用更少的代码重写了这些视图,但我们还可以再进一步。REST框架提供了一组已经混合好(mixed-in)的通用视图,我们可以使用它来简化我们的views.py
模块。
######################### 使用通用得基于类得视图 ##############################
from rest_framework import generics
class AuthorView(generics.ListCreateAPIView):
queryset = Author.objects.all()
serializer_class = AuthorModelSerializers
class AuthorDetailView(generics.RetrieveUpdateDestroyAPIView):
queryset = Author.objects.all()
serializer_class = AuthorModelSerializers
3. viewsets.ModelViewSet
views.AuthorModelView.as_view({"get": "list", "post": "create"})
views.AuthorModelView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})
from rest_framework import viewsets
viewsets.ModelViewSet
url(r''^authors/$'', views.AuthorModelView.as_view({"get": "list", "post": "create"}), name="author"),
url(r''^authors/(?P<pk>\d+)'',
views.AuthorModelView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"}), name="detail_author"),
---------------------------------------------------
######################### viewsets.ModelViewSet ##############################
from rest_framework import viewsets
class AuthorModelView(viewsets.ModelViewSet):
queryset = Author.objects.all()
serializer_class = AuthorModelSerializers
# 可重写,覆盖!
# def list(self,request,*args,**kwargs):pass
效果:
get post get put delete 都可访问!


http://www.cnblogs.com/yuanchenqi/articles/8719520.html
视图三部曲
5中方法: 查(全部) 查(单条) 增 删 改
逻辑封装起来了
-----------------------------------
class AuthorModelView(viewsets.ModelViewSet):
queryset = Author.objects.all()
serializer_class = AuthorModelSerializers
(1):url(r''^authors/$'', views.AuthorModelView.as_view({"get":"list","post":"create"}), name=''author''),
(2):url(r''^authors/$'', ViewSetMixin.as_view({"get":"list","post":"create"}), name=''author''),
(3):url(r''^authors/$'', ViewsetMixin.View, name=''author''),
一旦用户 get 方式 访问 authors:
ViewsetMixin.View():
for method, action in actions.items(): # {"get":"list","post":"create"}
handler = getattr(self, action) # self.list self.create
setattr(self, method, handler) # self.get = self.list self.post = self.create
# getattr(self,"get") # self.list
# getattr(self,"post") # self.create
return self.dispatch()
APIView.dispatch():
if request.method.lower() in self.http_method_names:
handler = getattr(self,request.method.lower())
response = handler(request,*args,**kwargs) # self.list()
return response
(ViewSetMixin)
二、认证组件
生成随机字符串
import hashlib, time
def get_random_str(user):
""" 生成随机 字符串 """
ctime = str(time.time())
md5 = hashlib.md5(bytes(user,encoding=''utf-8''))
md5.update(bytes(ctime,encoding="utf-8"))
return md5.hexdigest()
update_or_create
# update_or_create
Token.objects.update_or_create(user=user,defaults={"token":random_str})
返回json
# import json
# from django.shortcuts import HttpResponse
# return HttpResponse(json.dumps(res,ensure_ascii=False))
# from django.http import JsonResponse
# return JsonResponse(res)
return Response(res)
登录,生成随机token
url(r''^login/$'', views.LoginView.as_view(), name="login")
---------------------------------------------
import hashlib, time
def get_random_str(user):
""" 生成随机 字符串 """
ctime = str(time.time())
md5 = hashlib.md5(bytes(user,encoding=''utf-8''))
md5.update(bytes(ctime,encoding="utf-8"))
return md5.hexdigest()
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:
random_str = get_random_str(user.name)
# update_or_create
Token.objects.update_or_create(user=user,defaults={"token":random_str})
res["token"] = random_str
else:
res["state_code"] = 1001 # 错误状态码
res["msg"] = "用户名或密码错误"
# import json
# from django.shortcuts import HttpResponse
# return HttpResponse(json.dumps(res,ensure_ascii=False))
# from django.http import JsonResponse
# return JsonResponse(res)
return Response(res)
--------------------------------------------------------
# models.py
class User(models.Model):
name = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
class Token(models.Model):
user = models.OneToOneField("User")
token = models.CharField(max_length=128)
def __str__(self):
return self.token
效果图:
登录验证 - 局部
authentication_classes = [TokenAuth]
from rest_framework import exceptions
from rest_framework.authentication import BaseAuthentication
def authenticate(self,request):
... ...
if not token_obj:
raise exceptions.AuthenticationFailed("验证失败")
return (token_obj.user.name, token_obj)
from rest_framework import exceptions
# class TokenAuth(object):
# def authenticate(self,request):
# token = request.GET.get("token")
# token_obj = Token.objects.filter(token=token).first()
# if not token_obj:
# raise exceptions.AuthenticationFailed("验证失败")
#
# return (token_obj.user.name, token_obj)
#
# def authenticate_header(self,request):
# pass
from rest_framework.authentication import BaseAuthentication
class TokenAuth(BaseAuthentication):
def authenticate(self,request):
token = request.GET.get("token")
token_obj = Token.objects.filter(token=token).first()
if not token_obj:
raise exceptions.AuthenticationFailed("验证失败")
return (token_obj.user.name, token_obj)
class BookView(APIView):
authentication_classes = [TokenAuth]
def get(self, request):
book_list = Book.objects.all()
ret = BookModelSerializers(book_list, many=True, context={"request": request})
return Response(ret.data)
def post(self, request):
bms = BookModelSerializers(data=request.data, many=False, context={"request": request})
if bms.is_valid():
bms.save()
return Response(bms.data)
else:
return Response(bms.errors)
登录验证 - 全局
settings 配置
''DEFAULT_AUTHENTICATION_CLASSES'': [''app01.utils.TokenAuth'']
# settings.py
REST_FRAMEWORK = {
''DEFAULT_AUTHENTICATION_CLASSES'': [''app01.utils.TokenAuth'']
}
-------------------------------------------
# app01.utils
from .models import *
from rest_framework import exceptions
from rest_framework.authentication import BaseAuthentication
class TokenAuth(BaseAuthentication):
def authenticate(self,request):
token = request.GET.get("token")
token_obj = Token.objects.filter(token=token).first()
if not token_obj:
raise exceptions.AuthenticationFailed("验证失败")
return (token_obj.user.name, token_obj)
--------------------------------------------
# views.py
class BookView(APIView):
def get(self, request):
book_list = Book.objects.all()
ret = BookModelSerializers(book_list, many=True, context={"request": request})
return Response(ret.data)
def post(self, request):
bms = BookModelSerializers(data=request.data, many=False, context={"request": request})
if bms.is_valid():
bms.save()
return Response(bms.data)
else:
return Response(bms.errors)
-----------------------------------------
class AuthorModelView(viewsets.ModelViewSet):
authentication_classes = [] # 加上这个,前提是全局有认证;加上这个,就走自己得,不认证了,自己没有,才走全局配置得!
queryset = Author.objects.all()
serializer_class = AuthorModelSerializers
效果图:
三、权限组件
权限 - 局部
permission_classes = [SVIPPermission]
has_permission(self,request,view):pass # 固定得写法,根据源码来写得!
authentication_classes = [] # 登录页面 不需要验证,在全局配置得前提下
class AuthorModelView(viewsets.ModelViewSet):
authentication_classes = [TokenAuth]
permission_classes = [SVIPPermission]
queryset = Author.objects.all()
serializer_class = AuthorModelSerializers
----------------------------------------------
# app01.utils.SVIPPermission
class SVIPPermission(object):
message = "只有超级用户才能访问"
def has_permission(self,request,view):
username = request.user
user_type = User.objects.filter(name=username).first().user_type
if user_type == 3:
return True
else:
return False
----------------------------------------------
class LoginView(APIView):
authentication_classes = []
...
...
权限 - 全局
settings配置:
''DEFAULT_PERMISSION_CLASSES'': [''app01.utils.SVIPPermission'']
# settings.py
REST_FRAMEWORK = {
''DEFAULT_AUTHENTICATION_CLASSES'': [''app01.utils.TokenAuth''],
''DEFAULT_PERMISSION_CLASSES'': [''app01.utils.SVIPPermission'']
}
效果图:
四、频率组件
局部视图throttle
class BookView(APIView):
# authentication_classes = [TokenAuth]
# permission_classes = [SVIPPermission]
throttle_classes = [VisitRateThrottle]
。。。 。。。
-----------------------------------------------
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])
全局视图throttle
REST_FRAMEWORK = {
''DEFAULT_AUTHENTICATION_CLASSES'': [''app01.utils.TokenAuth''],
''DEFAULT_PERMISSION_CLASSES'': [''app01.utils.SVIPPermission''],
''DEFAULT_THROTTLE_CLASSES'': [''app01.utils.VisitThrottle''],
}
内置throttle类
REST_FRAMEWORK = {
''DEFAULT_AUTHENTICATION_CLASSES'': [''app01.utils.TokenAuth''],
''DEFAULT_PERMISSION_CLASSES'': [''app01.utils.SVIPPermission''],
''DEFAULT_THROTTLE_CLASSES'': [''app01.utils.VisitThrottle''],
"DEFAULT_THROTTLE_RATES": {
"visit_rate": "1/m",
}
}
------------------------------------
from rest_framework.throttling import SimpleRateThrottle
class VisitThrottle(SimpleRateThrottle):
scope="visit_rate"
def get_cache_key(self, request, view):
return self.get_ident(request)
http://www.cnblogs.com/yuanchenqi/articles/8719520.html
五、解析器
from rest_framework.parsers import JSONParser,FormParser,MultiPartParser,FileUploadParser
"""
默认得是 JSONParser FormParser MultiPartParser
"""
class BookView(APIView):
parser_classes = [JSONParser,FormParser]
...
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'',]
}
六、url路由控制
url(r'''',include(routers.urls)),
from rest_framework import routers
routers = routers.DefaultRouter()
routers.register("authors",views.AuthorModelView)
# urls.py
from django.conf.urls import url,include
from django.contrib import admin
from app01 import views
from rest_framework import routers
routers = routers.DefaultRouter()
routers.register("authors",views.AuthorModelView)
urlpatterns = [
url(r''^admin/'', admin.site.urls),
url(r''^publishes/$'', views.PublishView.as_view(), name="publish"),
url(r''^publishes/(?P<pk>\d+)/$'', views.PublishDetailView.as_view(), name="detail_publish"),
url(r"^books/$", views.BookView.as_view(), name="books"),
url(r''^books/(?P<pk>\d+)/$'', views.BookDetailView.as_view(), name="detail_book"),
# url(r''^authors/$'',views.AuthorView.as_view(),name="author"),
# url(r''^authors/(?P<pk>\d+)'',views.AuthorDetailView.as_view(),name="detail_author"),
# url(r''^authors/$'', views.AuthorModelView.as_view({"get": "list", "post": "create"}), name="author"),
# url(r''^authors/(?P<pk>\d+)'',
# views.AuthorModelView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"}), name="detail_author"),
url(r'''',include(routers.urls)),
url(r''^login/$'', views.LoginView.as_view(), name="login")
]
------------------------------------------
# views.py
from rest_framework import viewsets
class AuthorModelView(viewsets.ModelViewSet):
queryset = Author.objects.all()
serializer_class = AuthorModelSerializers
效果图
七、分页
pnp = MyPageNumberPagination()
books_page = pnp.paginate_queryset(book_list,request,self)
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 = 2 # 限制 size 得大小 不能超过多少!!
class MyLimitOffsetPagination(LimitOffsetPagination):
default_limit = 1
---------------------------
class BookView(APIView):def get(self, request):
book_list = Book.objects.all()
pnp = MyPageNumberPagination()
# pnp = MyLimitOffsetPagination()
books_page = pnp.paginate_queryset(book_list,request,self)
# ret = BookModelSerializers(book_list, many=True, context={"request": request})
ret = BookModelSerializers(books_page, many=True)
# return Response(ret.data)
return pnp.get_paginated_response(ret.data)
from rest_framework import viewsets
class AuthorModelView(viewsets.ModelViewSet):
queryset = Author.objects.all()
serializer_class = AuthorModelSerializers
pagination_class = MyPageNumberPagination
效果图


day99
1 CBV
2 APIView
class BookView(APIView):pass
url(r''^books/$'', views.BookView.as_view(),name="books"),
url(r''^books/$'', View类下的view,name="books"),
一旦访问books/: view(request)======APIView类下的dispatch()====请求方式对应的示例方法()
3 def dispatch():
#一 初始化操作
# (1) 构建新的request:
self.request=self.initial_request()
# self.request._request
# self.request.GET
# self.request.data
# (2) 执行组件
# 认证,权限,频率
# 认证:request.user
self.initial(request, *args, **kwargs)
==== # 认证组件
self.perform_authentication(request)
==== request.user
=====
for authenticator in self.authenticators: # [TokenAuth(),]
try:
user_auth_tuple = authenticator.authenticate(self)
except exceptions.APIException:
self._not_authenticated()
raise
if user_auth_tuple is not None:
self._authenticator = authenticator
self.user, self.auth = user_auth_tuple
return
# 权限组件
self.check_permissions(request)
===========
for permission in self.get_permissions():
if not permission.has_permission(request, self):
self.permission_denied(
request, message=getattr(permission, ''message'', None)
)
# 频率组件
self.check_throttles(request)
=============
for throttle in self.get_throttles(): # [VisitRateThrottle(),]
if not throttle.allow_request(request, self):
self.throttled(request, throttle.wait()) # 受限制
# 分发
if request.method.lower() in self.http_method_names:
handler = getattr(self,request.method.lower(),
self.http_method_not_allowed)
response = handler(request, *args, **kwargs)
return response
4 序列化组件
class PublishSerializers(serializers.Serializer):
name = serializers.CharField()
email = serializers.CharField()
class PublishModelSerializers(serializers.ModelSerializer):
class Meta:
model=Publish
fields="__all__"
# queryset或者model对象-------------》json数据
ps=PublishSerializers(queryset,many=True)
ps.data # [{},{},{}]
ps=PublishSerializers(model_obj,many=False)
ps.data # {}
# json数据-------》记录
# 添加操作
ps=PublishSerializers(data=request.data)
if ps.is_valid():
ps.save() # create
# 更新操作
ps=PublishSerializers(model_obj,data=request.data)
if ps.is_valid():
ps.save() # update
5 视图组件
# 版本1:
# Book表
class BookView(APIView):
def get(self,request):
book_list=Book.objects.all()
bs=BookModelSerializers(book_list,many=True,context={''request'': request})
return Response(bs.data)
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)
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)
def delete(self,request,id):
Book.objects.filter(pk=id).delete()
return Response()
# 版本2:mixIn
from rest_framework import mixins
from rest_framework import generics
class AuthorView(mixins.ListModelMixin,mixins.CreateModelMixin,generics.GenericAPIView):
queryset=Author.objects.all()
serializer_class =AuthorModelSerializers
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 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)
# 版本3:基于通用类
from rest_framework import mixins
from rest_framework import generics
class AuthorView(generics.ListCreateAPIView):
queryset=Author.objects.all()
serializer_class =AuthorModelSerializers
class AuthorDetailView(generics.RetrieveUpdateDestroyAPIView):
queryset = Author.objects.all()
serializer_class = AuthorModelSerializers
# 版本4
class AuthorModelView(viewsets.ModelViewSet):
queryset = Author.objects.all()
serializer_class = AuthorModelSerializers
url(r''^authors/$'', views.AuthorModelView.as_view({"get":"list","post":"create"}),name="author"),
url(r''^authors/(?P<pk>\d+)/$'', views.AuthorModelView.as_view({"get":"retrieve","put"
流程:
url(r''^authors/$'', views.AuthorModelView.as_view({"get":"list","post":"create"}),name="author"),
url(r''^authors/$'', ViewSetMixin.as_view({"get":"list","post":"create"}),name="author"),
url(r''^authors/$'', ViewSetMixin类下的view),
一旦访问 /authors/:
ViewSetMixin
def view():
for method, action in actions.items(): # {"get":"list","post":"create"}
handler = getattr(self, action) # self.list self.create
setattr(self, method, handler)
self.dispatch(request, *args, **kwargs)
APIView类下的self.dispatch
# 分发
if request.method.lower() in self.http_method_names:
handler = getattr(self,request.method.lower(),
self.http_method_not_allowed)
response = handler(request, *args, **kwargs) # self.list()
return response
6 认证权限频率 组件
request.META:
{''ALLUSERSPROFILE'': ''C:\\ProgramData'',
''APPDATA'': ''C:\\Users\\Administrator\\AppData\\Roaming'',
''COMMONPROGRAMFILES'': ''C:\\Program Files\\Common Files'',
''COMMONPROGRAMFILES(X86)'': ''C:\\Program Files (x86)\\Common Files'',
''COMMONPROGRAMW6432'': ''C:\\Program Files\\Common Files'',
''COMPUTERNAME'': ''PC201712041709'',
''COMSPEC'': ''C:\\Windows\\system32\\cmd.exe'',
''DJANGO_SETTINGS_MODULE'': ''restdemo.settings'',
''FP_NO_HOST_CHECK'': ''NO'', ''HOMEDRIVE'': ''C:'',
''HOMEPATH'': ''\\Users\\Administrator'',
''LOCALAPPDATA'': ''C:\\Users\\Administrator\\AppData\\Local'',
''LOGONSERVER'': ''\\\\PC201712041709'',
''NUMBER_OF_PROCESSORS'': ''4'', ''OS'': ''Windows_NT'',
''PATH'': ''C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python36;C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python36\\Scripts;C:\\Python27;E:\\MySQL Server 5.6\\bin;C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python36\\Scripts\\;C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python36\\;C:\\Users\\Administrator\\AppData\\Local\\atom\\bin'',
''PATHEXT'': ''.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC'',
''PROCESSOR_ARCHITECTURE'': ''AMD64'',
''PROCESSOR_IDENTIFIER'': ''Intel64 Family 6 Model 60 Stepping 3, GenuineIntel'',
''PROCESSOR_LEVEL'': ''6'', ''PROCESSOR_REVISION'': ''3c03'',
''PROGRAMDATA'': ''C:\\ProgramData'',
''PROGRAMFILES'': ''C:\\Program Files'',
''PROGRAMFILES(X86)'': ''C:\\Program Files (x86)'',
''PROGRAMW6432'': ''C:\\Program Files'',
''PSMODULEPATH'': ''C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\Modules\\'',
''PUBLIC'': ''C:\\Users\\Public'', ''PYCHARM_HOSTED'': ''1'', ''PYTHONIOENCODING'': ''UTF-8'',
''PYTHONPATH'': ''C:\\Users\\Administrator\\PycharmProjects\\s9\\restdemo'', ''PYTHONUNBUFFERED'': ''1'',
''SESSIONNAME'': ''Console'', ''SYSTEMDRIVE'': ''C:'', ''SYSTEMROOT'': ''C:\\Windows'',
''TEMP'': ''C:\\Users\\ADMINI~1\\AppData\\Local\\Temp'', ''TMP'': ''C:\\Users\\ADMINI~1\\AppData\\Local\\Temp'',
''USERDOMAIN'': ''PC201712041709'',
''USERNAME'': ''Administrator'',
''USERPROFILE'': ''C:\\Users\\Administrator'',
''WINDIR'': ''C:\\Windows'', ''WINDOWS_TRACING_FLAGS'': ''3'',
''WINDOWS_TRACING_LOGFILE'': ''C:\\BVTBin\\Tests\\installpackage\\csilogfile.log'',
''RUN_MAIN'': ''true'', ''SERVER_NAME'': ''PC201712041709'',
''GATEWAY_INTERFACE'': ''CGI/1.1'', ''SERVER_PORT'': ''8000'',
''REMOTE_HOST'': '''',
''CONTENT_LENGTH'': '''',
''SCRIPT_NAME'': '''',
''SERVER_PROTOCOL'': ''HTTP/1.1'',
''SERVER_SOFTWARE'': ''WSGIServer/0.2'',
''REQUEST_METHOD'': ''GET'',
''PATH_INFO'': ''/authors/'',
''QUERY_STRING'': ''token=8204b8e3ac40bf59ae480d17c146b51a'',
''REMOTE_ADDR'': ''127.0.0.1'',
''CONTENT_TYPE'': ''text/plain'',
''HTTP_HOST'': ''127.0.0.1:8000'',
''HTTP_CONNECTION'': ''keep-alive'',
''HTTP_USER_AGENT'': ''Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'',
''HTTP_UPGRADE_INSECURE_REQUESTS'': ''1'',
''HTTP_ACCEPT'': ''text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8'',
''HTTP_ACCEPT_ENCODING'': ''gzip, deflate, br'', ''HTTP_ACCEPT_LANGUAGE'': ''zh-CN,zh;q=0.9'', ''HTTP_COOKIE'': ''csrftoken=jtus3l4GJEc9TFXWYCWxkBIZprcOv7C1vFMIyOHs7Zkxt015FwVZ2KEEeDV6LOyN'', ''wsgi.input'': <_io.BufferedReader name=832>, ''wsgi.errors'': <_io.TextIOWrapper name=''<stderr>'' mode=''w'' encoding=''UTF-8''>, ''wsgi.version'': (1, 0), ''wsgi.run_once'': False, ''wsgi.url_scheme'': ''http'', ''wsgi.multithread'': True, ''wsgi.multiprocess'': False, ''wsgi.file_wrapper'': <class ''wsgiref.util.FileWrapper''>}
7 解析器-----数据解析器
from rest_framework.parsers import JSONParser,FormParser,MultiPartParser,FileUploadParser
parser_classes = [JSONParser,FormParser]
8 路由控制
针对:
url(r''^authors/$'', views.AuthorModelView.as_view({"get":"list","post":"create"}),name="author"),
url(r''^authors/(?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
url(r''^books/$'', views.BookModelView.as_view({"get":"list","post":"create"}),name="author"),
url(r''^books/(?P<pk>\d+)/$'', views.BookModelView.as_view({"get":"retrieve","put":"update","delete":"destroy"}),name="detailbook"),
class AuthorModelView(viewsets.ModelViewSet):
queryset = Author.objects.all()
serializer_class = AuthorModelSerializers
9 分页
10 响应器 Response


REST_FRAMEWORK = {
# ''DEFAULT_AUTHENTICATION_CLASSES'': [''app01.utils.TokenAuth''],
# ''DEFAULT_PERMISSION_CLASSES'': [''app01.utils.SVIPPermission''],
# ''DEFAULT_THROTTLE_CLASSES'': [''app01.utils.VisitThrottle''],
# "DEFAULT_THROTTLE_RATES": {
# "visit_rate": "1/m",
# }
# "PAGE_SIZE":2
}


from django.conf.urls import url,include
from django.contrib import admin
from app01 import views
from rest_framework import routers
routers = routers.DefaultRouter()
routers.register("authors",views.AuthorModelView)
urlpatterns = [
url(r''^admin/'', admin.site.urls),
url(r''^publishes/$'', views.PublishView.as_view(), name="publish"),
url(r''^publishes/(?P<pk>\d+)/$'', views.PublishDetailView.as_view(), name="detail_publish"),
url(r"^books/$", views.BookView.as_view(), name="books"),
url(r''^books/(?P<pk>\d+)/$'', views.BookDetailView.as_view(), name="detail_book"),
# url(r''^authors/$'',views.AuthorView.as_view(),name="author"),
# url(r''^authors/(?P<pk>\d+)'',views.AuthorDetailView.as_view(),name="detail_author"),
# url(r''^authors/$'', views.AuthorModelView.as_view({"get": "list", "post": "create"}), name="author"),
# url(r''^authors/(?P<pk>\d+)'',
# views.AuthorModelView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"}), name="detail_author"),
url(r'''',include(routers.urls)),
url(r''^login/$'', views.LoginView.as_view(), name="login")
]


from .models import *
from rest_framework import exceptions
from rest_framework.authentication import BaseAuthentication
class TokenAuth(BaseAuthentication):
def authenticate(self,request):
token = request.GET.get("token")
token_obj = Token.objects.filter(token=token).first()
if not token_obj:
raise exceptions.AuthenticationFailed("验证失败")
return (token_obj.user.name, token_obj)
class SVIPPermission(object):
message = "只有超级用户才能访问"
def has_permission(self,request,view):
username = request.user
user_type = User.objects.filter(name=username).first().user_type
if user_type == 3:
return True
else:
return False
# 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])
from rest_framework.throttling import SimpleRateThrottle
class VisitThrottle(SimpleRateThrottle):
scope="visit_rate"
def get_cache_key(self, request, view):
return self.get_ident(request)


from django.shortcuts import render, HttpResponse
from django.views import View
from .models import *
import json
from rest_framework import serializers
from rest_framework.views import APIView
from rest_framework.response import Response
# 为queryset,model 对象 做序列化得
# class PublishSerializers(serializers.Serializer):
# name = serializers.CharField()
# email = serializers.CharField()
class PublishModelSerializers(serializers.ModelSerializer):
class Meta:
model = Publish
fields = "__all__"
class BookModelSerializers(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
# 显示超链接
publish = serializers.HyperlinkedIdentityField(
view_name=''detailpublish'', # 别名 含正则表达式
lookup_field= ''publish_id'',
lookup_url_kwarg=''pk''
)
# publish = serializers.CharField(source="publish.pk")
# publish = serializers.CharField()
# 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
# def create(self, validated_data):
# print(''--->'',validated_data)
# book = Book.objects.create(title=validated_data["title"],price=validated_data[''price''],
# pub_date=validated_data[''pub_date''],publish_id=validated_data[''publish''][''pk''])
# book.authors.add(*validated_data[''authors''])
#
# return book
class AuthorModelSerializers(serializers.ModelSerializer):
class Meta:
model = Author
fields = "__all__"


from django.db import models
# Create your models here.
class User(models.Model):
name = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
type_choices = ((1,"普通用户"),(2,"VIP"),(3,"SVIP"))
user_type = models.IntegerField(choices=type_choices,default=1)
class Token(models.Model):
user = models.OneToOneField("User")
token = models.CharField(max_length=128)
def __str__(self):
return self.token
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


from django.shortcuts import render,HttpResponse
# Create your views here.
from django.views import View
from .models import *
import json
from rest_framework import serializers
from rest_framework.views import APIView
from rest_framework.response import Response
from app01.serializer import *
class PublishView(APIView):
def get(self, request):
publish_list = Publish.objects.all()
ret = PublishModelSerializers(publish_list, many=True)
return Response(ret.data)
def post(self, request):
ps = PublishModelSerializers(data=request.data)
if ps.is_valid():
ps.save()
return Response(ps.data)
else:
return Response(ps.errors)
class PublishDetailView(APIView):
def get(self, request, pk):
publish = Publish.objects.filter(pk=pk).first()
ps = PublishModelSerializers(publish)
return Response(ps.data)
def put(self, request, pk):
publish = Publish.objects.filter(pk=pk).first()
ps = PublishModelSerializers(publish, data=request.data)
if ps.is_valid():
ps.save()
return Response(ps.data)
else:
return Response(ps.errors)
def delete(self, request, pk):
Publish.objects.filter(pk=pk).delete()
return Response()
from rest_framework.parsers import JSONParser,FormParser,MultiPartParser,FileUploadParser
"""
默认得是 JSONParser FormParser MultiPartParser
"""
# Book
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination
class MyPageNumberPagination(PageNumberPagination):
page_size = 1
page_query_param = "page"
page_size_query_param = "size"
max_page_size = 2 # 限制 size 得大小 不能超过多少!!
# # http://127.0.0.1:8000/books/?page=2&size=2
class MyLimitOffsetPagination(LimitOffsetPagination):
default_limit = 1
# limit_query_param =
# http://127.0.0.1:8000/books/?limit=2&offset=2
# 偏移
class BookView(APIView):
# authentication_classes = [TokenAuth]
parser_classes = [JSONParser,FormParser]
def get(self,request):
print("user:--->", request.user)
print(request.auth)
book_list = Book.objects.all()
# 分页 page_size 配置 setting 全局得 单独怎么设置? 写个类
# from rest_framework.pagination import PageNumberPagination
# pnp = PageNumberPagination()
# pnp = MyPageNumberPagination()
pnp = MyLimitOffsetPagination()
books_page = pnp.paginate_queryset(book_list,request,self)
# bs = BookModelSerializers(book_list,many=True,context={''request'': request})
bs = BookModelSerializers(books_page,many=True,context={''request'': request})
# return HttpResponse(bs.data)
return Response(bs.data)
def post(self,request):
print(''data:--->'', request.data,type(request.data))
# post 请求的数据
bs = BookModelSerializers(data=request.data,context={''request'': request})
if bs.is_valid():
bs.save() # create 方法
print(bs.validated_data)
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)
return Response(bs.data)
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)
def delete(self,request,id):
Book.objects.filter(pk=id).delete()
return Response()
# Author
# 逻辑复用
# 三种方法
######################### mixin类编写视图 ##############################
# from rest_framework import mixins, generics
#
# class AuthorView(mixins.ListModelMixin,mixins.CreateModelMixin,generics.GenericAPIView):
# queryset = Author.objects.all()
# serializer_class = AuthorModelSerializers
#
# def get(self,request,*args,**kwargs):
# return self.list(request,*args,**kwargs)
#
# def post(self,request,*args,**kwargs):
# return self.create(self, request, *args, **kwargs)
#
#
# class AuthorDetailView(mixins.RetrieveModelMixin,mixins.DestroyModelMixin,mixins.UpdateModelMixin,generics.GenericAPIView):
# queryset = Author.objects.all()
# serializer_class = AuthorModelSerializers
#
# def get(self,request,pk,*args,**kwargs):
# return self.retrieve(request,pk,*args,**kwargs)
#
# def delete(self,request,*args,**kwargs):
# return self.destroy(request,*args,**kwargs)
#
# def put(self,request,*args,**kwargs):
# return self.update(request,*args,**kwargs)
######################### 使用得通用得基于类得视图 ##############################
# from rest_framework import mixins, generics
#
# class AuthorView(generics.ListCreateAPIView):
# queryset = Author.objects.all()
# serializer_class = AuthorModelSerializers
#
#
# class AuthorDetailView(generics.RetrieveUpdateDestroyAPIView):
# queryset = Author.objects.all()
# serializer_class = AuthorModelSerializers
######################### viewsets.ModelViewSet ##############################
# url 需要是一趟线 走一个视图类
# url 中 利用参数 来指定 什么方式 用什么方法 执行
from .utils import TokenAuth,SVIPPermission
from rest_framework import viewsets
class VisitRateThrottle(object):
def allow_request(self,request,view):
# 要求访问站点得频率不能超过每分钟20次
if 1:
# 每次来 存下来 比对一下,间隔多久 超过一分钟
# IP, 请求首行(request.method request.path)
# 请求头(request.meta) 请求体(request.body)
print("meta:----->",request.META)
print(request.META.get("REMOTE_ADDR")) # 客户端得ip 这里面 你要保存什么 ip 时间 记录下来;
# 频率 限制 实现 功能!!!
return True
else:
return False
from rest_framework.response import Response
class AuthorModelView(viewsets.ModelViewSet):
# authentication_classes = [TokenAuth,]
# permission_classes = [SVIPPermission,] 取配全局八
# throttle_classes = [VisitRateThrottle]
queryset = Author.objects.all()
serializer_class = AuthorModelSerializers
pagination_class = MyPageNumberPagination
# 完美! ok
# 类得继承 , 表示形式 需求 展示 数据 ,覆盖方法 单独写 类得继承 可重写 覆盖
#
# def list(self,request,*args,**kwargs):
# pass
# ------------------------------------------------------
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()
class LoginView(APIView):
authentication_classes = []
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:
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["status_code"] = 1001 # 错误状态码
res[''msg''] = "用户名或密码错误"
import json
return Response(json.dumps(res,ensure_ascii=False))
八、渲染器、版本
配置:
1.添加配置
REST_FRAMEWORK = {
''DEFAULT_RENDERER_CLASSES'':[''rest_framework.renderers.JSONRenderer'',''rest_framework.renderers.BrowsableAPIRenderer''],
''DEFAULT_VERSIONING_CLASS'': ''rest_framework.versioning.URLPathVersioning'',
''ALLOWED_VERSIONS'': [''v1'', ''v2''], # 允许的版本
''VERSION_PARAM'': ''version'', # 参数
''DEFAULT_VERSION'': ''v1'', # 默认版本
}
2.设置路由:
luffycity/urls.py
from django.conf.urls import url,include
from django.contrib import admin
urlpatterns = [
# url(r''^admin/'', admin.site.urls),
url(r''^api/(?P<version>\w+)/'', include(''api.urls'')),
]
api/urls.py
from django.conf.urls import url
from api.views import course
urlpatterns = [
url(r''^course/$'', course.CourseView.as_view()),
]
3.获取版本
request.version 获取版本
django - 插件 django REST framework, 返回序列化的数据
官网: http://www.django-rest-framework.org
1. 安装
pip install djangorestframework
2. 在 setting.py 中注册 app 中添加 ''rest_framework''
序列化功能,官网中
使用的案例部分代码,直观的显示使用方法:
第一步:调用 rest_framework 进行序列化
# -*- coding: utf-8 -*-
from rest_framework import serializers
from .models import User, News, NewCategory
# 指定author序列化字段,为了News序列化
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = (''telephone'', ''username'', ''is_active'', ''gender'', ''email'', ''data_joined'')
# 指定category序列化字段,为了New序列化
class NewsCategorySerializers(serializers.ModelSerializer):
class Meta:
model = NewsCategory
fields = (''id'', ''name'')
class NewsSerializers(serializers.ModelSerializer):
category = NewsCategorySerializers() # 指定外键字段序列化
author = UserSerializer()
class Meta:
model = News
# 这里的category和author是News中的外键字段需要额外指定序列化字段
fields = (''id'', ''title'', ''desc'', ''thumbnail'', ''pubtime'', ''category'', ''author'')
第二步:调用获取数据
import NewsSerializer
newses = News.objects.all() # 注意这儿不要改动QuerySet类型,比如别使用value
serializer = NewsSerializers(newses, many=True) # many代表外键字段取多个字段
newses = serializer.data # 获取serializer的json数据
Django Rest Framework
原文链接:https://www.cnblogs.com/maple-shaw/p/7865767.html
一. 什么是RESTful
- REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”
- REST从资源的角度类审视整个网络,它将分布在网络中某个节点的资源通过URL进行标识,客户端应用通过URL来获取资源的表征,获得这些表征致使这些应用转变状态
- 所有的数据,不过是通过网络获取的还是操作(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其他架构风格的最本质属性
- 对于REST这种面向资源的架构风格,有人提出一种全新的结构理念,即:面向资源架构(ROA:Resource Oriented Architecture)
二. RESTful API设计
- API与用户的通信协议,总是使用HTTPs协议。
- 域名
- https://api.example.com 尽量将API部署在专用域名(会存在跨域问题)
- https://example.org/api/ API很简单
- 版本
- URL,如:https://api.example.com/v1/
- 请求头 跨域时,引发发送多次请求
- 路径,视网络上任何东西都是资源,均使用名词表示(可复数)
- https://api.example.com/v1/zoos
- https://api.example.com/v1/animals
- https://api.example.com/v1/employees
- method
- GET :从服务器取出资源(一项或多项)
- POST :在服务器新建一个资源
- PUT :在服务器更新资源(客户端提供改变后的完整资源)
- PATCH :在服务器更新资源(客户端提供改变的属性)
- DELETE :从服务器删除资源
- 过滤,通过在url上传参的形式传递搜索条件
- https://api.example.com/v1/zoos?limit=10:指定返回记录的数量
- https://api.example.com/v1/zoos?offset=10:指定返回记录的开始位置
- https://api.example.com/v1/zoos?page=2&per_page=100:指定第几页,以及每页的记录数
- https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序
- https://api.example.com/v1/zoos?animal_type_id=1:指定筛选条件
- 状态码
200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务) 204 NO CONTENT - [DELETE]:用户删除数据成功。 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。 403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。 406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。 更多看这里:http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
- 错误处理,状态码是4xx时,应返回错误信息,error当做key。
123{
error:
"Invalid API key"
}
- 返回结果,针对不同操作,服务器向用户返回的结果应该符合以下规范。
123456GET
/
collection:返回资源对象的列表(数组)
GET
/
collection
/
resource:返回单个资源对象
POST
/
collection:返回新生成的资源对象
PUT
/
collection
/
resource:返回完整的资源对象
PATCH
/
collection
/
resource:返回完整的资源对象
DELETE
/
collection
/
resource:返回一个空文档
- Hypermedia API,RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。
123456{
"link"
: {
"rel"
:
"collection https://www.example.com/zoos"
,
"href"
:
"https://api.example.com/zoos"
,
"title"
:
"List of zoos"
,
"type"
:
"application/vnd.yourformat+json"
}}
摘自:http://www.ruanyifeng.com/blog/2014/05/restful_api.html
三. 基于Django实现
路由系统:
1
2
3
|
urlpatterns
=
[
url(r
''^users''
, Users.as_view()),
]
|
CBV视图:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
from
django.views
import
View
from
django.http
import
JsonResponse
class
Users(View):
def
get(
self
, request,
*
args,
*
*
kwargs):
result
=
{
''status''
:
True
,
''data''
:
''response data''
}
return
JsonResponse(result, status
=
200
)
def
post(
self
, request,
*
args,
*
*
kwargs):
result
=
{
''status''
:
True
,
''data''
:
''response data''
}
return
JsonResponse(result, status
=
200
)
|
四. 基于Django Rest Framework框架实现
1. 基本流程
url.py
1
2
3
4
5
6
|
from
django.conf.urls
import
url, include
from
web.views.s1_api
import
TestView
urlpatterns
=
[
url(r
''^test/''
, TestView.as_view()),
]
|
views.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
from
rest_framework.views
import
APIView
from
rest_framework.response
import
Response
class
TestView(APIView):
def
dispatch(
self
, request,
*
args,
*
*
kwargs):
"""
请求到来之后,都要执行dispatch方法,dispatch方法根据请求方式不同触发 get/post/put等方法
注意:APIView中的dispatch方法有好多好多的功能
"""
return
super
().dispatch(request,
*
args,
*
*
kwargs)
def
get(
self
, request,
*
args,
*
*
kwargs):
return
Response(
''GET请求,响应内容''
)
def
post(
self
, request,
*
args,
*
*
kwargs):
return
Response(
''POST请求,响应内容''
)
def
put(
self
, request,
*
args,
*
*
kwargs):
return
Response(
''PUT请求,响应内容''
)
|
上述是rest framework框架基本流程,重要的功能是在APIView的dispatch中触发。
2. 认证和授权
a. 用户url传入的token认证

from django.conf.urls import url, include
from web.viewsimport TestView
urlpatterns = [
url(r''^test/'', TestView.as_view()),
]


from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import BaseAuthentication
from rest_framework.request import Request
from rest_framework import exceptions
token_list = [
''sfsfss123kuf3j123'',
''asijnfowerkkf9812'',
]
class TestAuthentication(BaseAuthentication):
def authenticate(self, request):
"""
用户认证,如果验证成功后返回元组: (用户,用户Token)
:param request:
:return:
None,表示跳过该验证;
如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
self._authenticator = None
if api_settings.UNAUTHENTICATED_USER:
self.user = api_settings.UNAUTHENTICATED_USER()
else:
self.user = None
if api_settings.UNAUTHENTICATED_TOKEN:
self.auth = api_settings.UNAUTHENTICATED_TOKEN()
else:
self.auth = None
(user,token)表示验证通过并设置用户名和Token;
AuthenticationFailed异常
"""
val = request.query_params.get(''token'')
if val not in token_list:
raise exceptions.AuthenticationFailed("用户认证失败")
return (''登录用户'', ''用户token'')
def authenticate_header(self, request):
"""
Return a string to be used as the value of the `WWW-Authenticate`
header in a `401 Unauthenticated` response, or `None` if the
authentication scheme should return `403 Permission Denied` responses.
"""
# 验证失败时,返回的响应头WWW-Authenticate对应的值
pass
class TestView(APIView):
authentication_classes = [TestAuthentication, ]
permission_classes = []
def get(self, request, *args, **kwargs):
print(request.user)
print(request.auth)
return Response(''GET请求,响应内容'')
def post(self, request, *args, **kwargs):
return Response(''POST请求,响应内容'')
def put(self, request, *args, **kwargs):
return Response(''PUT请求,响应内容'')

b. 请求头认证

from django.conf.urls import url, include
from web.viewsimport TestView
urlpatterns = [
url(r''^test/'', TestView.as_view()),
]


#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import BaseAuthentication
from rest_framework.request import Request
from rest_framework import exceptions
token_list = [
''sfsfss123kuf3j123'',
''asijnfowerkkf9812'',
]
class TestAuthentication(BaseAuthentication):
def authenticate(self, request):
"""
用户认证,如果验证成功后返回元组: (用户,用户Token)
:param request:
:return:
None,表示跳过该验证;
如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
self._authenticator = None
if api_settings.UNAUTHENTICATED_USER:
self.user = api_settings.UNAUTHENTICATED_USER()
else:
self.user = None
if api_settings.UNAUTHENTICATED_TOKEN:
self.auth = api_settings.UNAUTHENTICATED_TOKEN()
else:
self.auth = None
(user,token)表示验证通过并设置用户名和Token;
AuthenticationFailed异常
"""
import base64
auth = request.META.get(''HTTP_AUTHORIZATION'', b'''')
if auth:
auth = auth.encode(''utf-8'')
auth = auth.split()
if not auth or auth[0].lower() != b''basic'':
raise exceptions.AuthenticationFailed(''验证失败'')
if len(auth) != 2:
raise exceptions.AuthenticationFailed(''验证失败'')
username, part, password = base64.b64decode(auth[1]).decode(''utf-8'').partition('':'')
if username == ''alex'' and password == ''123'':
return (''登录用户'', ''用户token'')
else:
raise exceptions.AuthenticationFailed(''用户名或密码错误'')
def authenticate_header(self, request):
"""
Return a string to be used as the value of the `WWW-Authenticate`
header in a `401 Unauthenticated` response, or `None` if the
authentication scheme should return `403 Permission Denied` responses.
"""
return ''Basic realm=api''
class TestView(APIView):
authentication_classes = [TestAuthentication, ]
permission_classes = []
def get(self, request, *args, **kwargs):
print(request.user)
print(request.auth)
return Response(''GET请求,响应内容'')
def post(self, request, *args, **kwargs):
return Response(''POST请求,响应内容'')
def put(self, request, *args, **kwargs):
return Response(''PUT请求,响应内容'')

c. 多个认证规则

from django.conf.urls import url, include
from web.views.s2_auth import TestView
urlpatterns = [
url(r''^test/'', TestView.as_view()),
]


#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import BaseAuthentication
from rest_framework.request import Request
from rest_framework import exceptions
token_list = [
''sfsfss123kuf3j123'',
''asijnfowerkkf9812'',
]
class Test1Authentication(BaseAuthentication):
def authenticate(self, request):
"""
用户认证,如果验证成功后返回元组: (用户,用户Token)
:param request:
:return:
None,表示跳过该验证;
如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
self._authenticator = None
if api_settings.UNAUTHENTICATED_USER:
self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户
else:
self.user = None
if api_settings.UNAUTHENTICATED_TOKEN:
self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默认值为:None
else:
self.auth = None
(user,token)表示验证通过并设置用户名和Token;
AuthenticationFailed异常
"""
import base64
auth = request.META.get(''HTTP_AUTHORIZATION'', b'''')
if auth:
auth = auth.encode(''utf-8'')
else:
return None
print(auth,''xxxx'')
auth = auth.split()
if not auth or auth[0].lower() != b''basic'':
raise exceptions.AuthenticationFailed(''验证失败'')
if len(auth) != 2:
raise exceptions.AuthenticationFailed(''验证失败'')
username, part, password = base64.b64decode(auth[1]).decode(''utf-8'').partition('':'')
if username == ''alex'' and password == ''123'':
return (''登录用户'', ''用户token'')
else:
raise exceptions.AuthenticationFailed(''用户名或密码错误'')
def authenticate_header(self, request):
"""
Return a string to be used as the value of the `WWW-Authenticate`
header in a `401 Unauthenticated` response, or `None` if the
authentication scheme should return `403 Permission Denied` responses.
"""
# return ''Basic realm=api''
pass
class Test2Authentication(BaseAuthentication):
def authenticate(self, request):
"""
用户认证,如果验证成功后返回元组: (用户,用户Token)
:param request:
:return:
None,表示跳过该验证;
如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
self._authenticator = None
if api_settings.UNAUTHENTICATED_USER:
self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户
else:
self.user = None
if api_settings.UNAUTHENTICATED_TOKEN:
self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默认值为:None
else:
self.auth = None
(user,token)表示验证通过并设置用户名和Token;
AuthenticationFailed异常
"""
val = request.query_params.get(''token'')
if val not in token_list:
raise exceptions.AuthenticationFailed("用户认证失败")
return (''登录用户'', ''用户token'')
def authenticate_header(self, request):
"""
Return a string to be used as the value of the `WWW-Authenticate`
header in a `401 Unauthenticated` response, or `None` if the
authentication scheme should return `403 Permission Denied` responses.
"""
pass
class TestView(APIView):
authentication_classes = [Test1Authentication, Test2Authentication]
permission_classes = []
def get(self, request, *args, **kwargs):
print(request.user)
print(request.auth)
return Response(''GET请求,响应内容'')
def post(self, request, *args, **kwargs):
return Response(''POST请求,响应内容'')
def put(self, request, *args, **kwargs):
return Response(''PUT请求,响应内容'')

d. 认证和权限

from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r''^test/'', TestView.as_view()),
]


#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import BaseAuthentication
from rest_framework.permissions import BasePermission
from rest_framework.request import Request
from rest_framework import exceptions
token_list = [
''sfsfss123kuf3j123'',
''asijnfowerkkf9812'',
]
class TestAuthentication(BaseAuthentication):
def authenticate(self, request):
"""
用户认证,如果验证成功后返回元组: (用户,用户Token)
:param request:
:return:
None,表示跳过该验证;
如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
self._authenticator = None
if api_settings.UNAUTHENTICATED_USER:
self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户
else:
self.user = None
if api_settings.UNAUTHENTICATED_TOKEN:
self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默认值为:None
else:
self.auth = None
(user,token)表示验证通过并设置用户名和Token;
AuthenticationFailed异常
"""
val = request.query_params.get(''token'')
if val not in token_list:
raise exceptions.AuthenticationFailed("用户认证失败")
return (''登录用户'', ''用户token'')
def authenticate_header(self, request):
"""
Return a string to be used as the value of the `WWW-Authenticate`
header in a `401 Unauthenticated` response, or `None` if the
authentication scheme should return `403 Permission Denied` responses.
"""
pass
class TestPermission(BasePermission):
message = "权限验证失败"
def has_permission(self, request, view):
"""
判断是否有权限访问当前请求
Return `True` if permission is granted, `False` otherwise.
:param request:
:param view:
:return: True有权限;False无权限
"""
if request.user == "管理员":
return True
# GenericAPIView中get_object时调用
def has_object_permission(self, request, view, obj):
"""
视图继承GenericAPIView,并在其中使用get_object时获取对象时,触发单独对象权限验证
Return `True` if permission is granted, `False` otherwise.
:param request:
:param view:
:param obj:
:return: True有权限;False无权限
"""
if request.user == "管理员":
return True
class TestView(APIView):
# 认证的动作是由request.user触发
authentication_classes = [TestAuthentication, ]
# 权限
# 循环执行所有的权限
permission_classes = [TestPermission, ]
def get(self, request, *args, **kwargs):
# self.dispatch
print(request.user)
print(request.auth)
return Response(''GET请求,响应内容'')
def post(self, request, *args, **kwargs):
return Response(''POST请求,响应内容'')
def put(self, request, *args, **kwargs):
return Response(''PUT请求,响应内容'')

e. 全局使用
上述操作中均是对单独视图进行特殊配置,如果想要对全局进行配置,则需要再配置文件中写入即可。


REST_FRAMEWORK = {
''UNAUTHENTICATED_USER'': None,
''UNAUTHENTICATED_TOKEN'': None,
"DEFAULT_AUTHENTICATION_CLASSES": [
"web.utils.TestAuthentication",
],
"DEFAULT_PERMISSION_CLASSES": [
"web.utils.TestPermission",
],
}


from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r''^test/'', TestView.as_view()),
]


#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
class TestView(APIView):
def get(self, request, *args, **kwargs):
# self.dispatch
print(request.user)
print(request.auth)
return Response(''GET请求,响应内容'')
def post(self, request, *args, **kwargs):
return Response(''POST请求,响应内容'')
def put(self, request, *args, **kwargs):
return Response(''PUT请求,响应内容'')

3. 用户访问次数/频率限制
a. 基于用户IP限制访问频率

from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r''^test/'', TestView.as_view()),
]


#!/usr/bin/env python
# -*- coding:utf-8 -*-
import time
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import exceptions
from rest_framework.throttling import BaseThrottle
from rest_framework.settings import api_settings
# 保存访问记录
RECORD = {
''用户IP'': [12312139, 12312135, 12312133, ]
}
class TestThrottle(BaseThrottle):
ctime = time.time
def get_ident(self, request):
"""
根据用户IP和代理IP,当做请求者的唯一IP
Identify the machine making the request by parsing HTTP_X_FORWARDED_FOR
if present and number of proxies is > 0. If not use all of
HTTP_X_FORWARDED_FOR if it is available, if not use REMOTE_ADDR.
"""
xff = request.META.get(''HTTP_X_FORWARDED_FOR'')
remote_addr = request.META.get(''REMOTE_ADDR'')
num_proxies = api_settings.NUM_PROXIES
if num_proxies is not None:
if num_proxies == 0 or xff is None:
return remote_addr
addrs = xff.split('','')
client_addr = addrs[-min(num_proxies, len(addrs))]
return client_addr.strip()
return ''''.join(xff.split()) if xff else remote_addr
def allow_request(self, request, view):
"""
是否仍然在允许范围内
Return `True` if the request should be allowed, `False` otherwise.
:param request:
:param view:
:return: True,表示可以通过;False表示已超过限制,不允许访问
"""
# 获取用户唯一标识(如:IP)
# 允许一分钟访问10次
num_request = 10
time_request = 60
now = self.ctime()
ident = self.get_ident(request)
self.ident = ident
if ident not in RECORD:
RECORD[ident] = [now, ]
return True
history = RECORD[ident]
while history and history[-1] <= now - time_request:
history.pop()
if len(history) < num_request:
history.insert(0, now)
return True
def wait(self):
"""
多少秒后可以允许继续访问
Optionally, return a recommended number of seconds to wait before
the next request.
"""
last_time = RECORD[self.ident][0]
now = self.ctime()
return int(60 + last_time - now)
class TestView(APIView):
throttle_classes = [TestThrottle, ]
def get(self, request, *args, **kwargs):
# self.dispatch
print(request.user)
print(request.auth)
return Response(''GET请求,响应内容'')
def post(self, request, *args, **kwargs):
return Response(''POST请求,响应内容'')
def put(self, request, *args, **kwargs):
return Response(''PUT请求,响应内容'')
def throttled(self, request, wait):
"""
访问次数被限制时,定制错误信息
"""
class Throttled(exceptions.Throttled):
default_detail = ''请求被限制.''
extra_detail_singular = ''请 {wait} 秒之后再重试.''
extra_detail_plural = ''请 {wait} 秒之后再重试.''
raise Throttled(wait)

b. 基于用户IP显示访问频率(利于Django缓存)

REST_FRAMEWORK = {
''DEFAULT_THROTTLE_RATES'': {
''test_scope'': ''10/m'',
},
}

from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r''^test/'', TestView.as_view()),
]


#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import exceptions
from rest_framework.throttling import SimpleRateThrottle
class TestThrottle(SimpleRateThrottle):
# 配置文件定义的显示频率的Key
scope = "test_scope"
def get_cache_key(self, request, view):
"""
Should return a unique cache-key which can be used for throttling.
Must be overridden.
May return `None` if the request should not be throttled.
"""
if not request.user:
ident = self.get_ident(request)
else:
ident = request.user
return self.cache_format % {
''scope'': self.scope,
''ident'': ident
}
class TestView(APIView):
throttle_classes = [TestThrottle, ]
def get(self, request, *args, **kwargs):
# self.dispatch
print(request.user)
print(request.auth)
return Response(''GET请求,响应内容'')
def post(self, request, *args, **kwargs):
return Response(''POST请求,响应内容'')
def put(self, request, *args, **kwargs):
return Response(''PUT请求,响应内容'')
def throttled(self, request, wait):
"""
访问次数被限制时,定制错误信息
"""
class Throttled(exceptions.Throttled):
default_detail = ''请求被限制.''
extra_detail_singular = ''请 {wait} 秒之后再重试.''
extra_detail_plural = ''请 {wait} 秒之后再重试.''
raise Throttled(wait)

c. view中限制请求频率

REST_FRAMEWORK = {
''DEFAULT_THROTTLE_RATES'': {
''xxxxxx'': ''10/m'',
},
}

from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r''^test/'', TestView.as_view()),
]


#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import exceptions
from rest_framework.throttling import ScopedRateThrottle
# 继承 ScopedRateThrottle
class TestThrottle(ScopedRateThrottle):
def get_cache_key(self, request, view):
"""
Should return a unique cache-key which can be used for throttling.
Must be overridden.
May return `None` if the request should not be throttled.
"""
if not request.user:
ident = self.get_ident(request)
else:
ident = request.user
return self.cache_format % {
''scope'': self.scope,
''ident'': ident
}
class TestView(APIView):
throttle_classes = [TestThrottle, ]
# 在settings中获取 xxxxxx 对应的频率限制值
throttle_scope = "xxxxxx"
def get(self, request, *args, **kwargs):
# self.dispatch
print(request.user)
print(request.auth)
return Response(''GET请求,响应内容'')
def post(self, request, *args, **kwargs):
return Response(''POST请求,响应内容'')
def put(self, request, *args, **kwargs):
return Response(''PUT请求,响应内容'')
def throttled(self, request, wait):
"""
访问次数被限制时,定制错误信息
"""
class Throttled(exceptions.Throttled):
default_detail = ''请求被限制.''
extra_detail_singular = ''请 {wait} 秒之后再重试.''
extra_detail_plural = ''请 {wait} 秒之后再重试.''
raise Throttled(wait)

d. 匿名时用IP限制+登录时用Token限制


REST_FRAMEWORK = {
''UNAUTHENTICATED_USER'': None,
''UNAUTHENTICATED_TOKEN'': None,
''DEFAULT_THROTTLE_RATES'': {
''luffy_anon'': ''10/m'',
''luffy_user'': ''20/m'',
},
}


from django.conf.urls import url, include
from web.views.s3_throttling import TestView
urlpatterns = [
url(r''^test/'', TestView.as_view()),
]


#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.throttling import SimpleRateThrottle
class LuffyAnonRateThrottle(SimpleRateThrottle):
"""
匿名用户,根据IP进行限制
"""
scope = "luffy_anon"
def get_cache_key(self, request, view):
# 用户已登录,则跳过 匿名频率限制
if request.user:
return None
return self.cache_format % {
''scope'': self.scope,
''ident'': self.get_ident(request)
}
class LuffyUserRateThrottle(SimpleRateThrottle):
"""
登录用户,根据用户token限制
"""
scope = "luffy_user"
def get_ident(self, request):
"""
认证成功时:request.user是用户对象;request.auth是token对象
:param request:
:return:
"""
# return request.auth.token
return "user_token"
def get_cache_key(self, request, view):
"""
获取缓存key
:param request:
:param view:
:return:
"""
# 未登录用户,则跳过 Token限制
if not request.user:
return None
return self.cache_format % {
''scope'': self.scope,
''ident'': self.get_ident(request)
}
class TestView(APIView):
throttle_classes = [LuffyUserRateThrottle, LuffyAnonRateThrottle, ]
def get(self, request, *args, **kwargs):
# self.dispatch
print(request.user)
print(request.auth)
return Response(''GET请求,响应内容'')
def post(self, request, *args, **kwargs):
return Response(''POST请求,响应内容'')
def put(self, request, *args, **kwargs):
return Response(''PUT请求,响应内容'')

e. 全局使用


REST_FRAMEWORK = {
''DEFAULT_THROTTLE_CLASSES'': [
''api.utils.throttles.throttles.LuffyAnonRateThrottle'',
''api.utils.throttles.throttles.LuffyUserRateThrottle'',
],
''DEFAULT_THROTTLE_RATES'': {
''anon'': ''10/day'',
''user'': ''10/day'',
''luffy_anon'': ''10/m'',
''luffy_user'': ''20/m'',
},
}

4. 版本
a. 基于url的get传参方式
如:/users?version=v1

REST_FRAMEWORK = {
''DEFAULT_VERSION'': ''v1'', # 默认版本
''ALLOWED_VERSIONS'': [''v1'', ''v2''], # 允许的版本
''VERSION_PARAM'': ''version'' # URL中获取值的key
}

from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r''^test/'', TestView.as_view(),name=''test''),
]


#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import QueryParameterVersioning
class TestView(APIView):
versioning_class = QueryParameterVersioning
def get(self, request, *args, **kwargs):
# 获取版本
print(request.version)
# 获取版本管理的类
print(request.versioning_scheme)
# 反向生成URL
reverse_url = request.versioning_scheme.reverse(''test'', request=request)
print(reverse_url)
return Response(''GET请求,响应内容'')
def post(self, request, *args, **kwargs):
return Response(''POST请求,响应内容'')
def put(self, request, *args, **kwargs):
return Response(''PUT请求,响应内容'')

b. 基于url的正则方式
如:/v1/users/

REST_FRAMEWORK = {
''DEFAULT_VERSION'': ''v1'', # 默认版本
''ALLOWED_VERSIONS'': [''v1'', ''v2''], # 允许的版本
''VERSION_PARAM'': ''version'' # URL中获取值的key
}

from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r''^(?P<version>[v1|v2]+)/test/'', TestView.as_view(), name=''test''),
]


#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import URLPathVersioning
class TestView(APIView):
versioning_class = URLPathVersioning
def get(self, request, *args, **kwargs):
# 获取版本
print(request.version)
# 获取版本管理的类
print(request.versioning_scheme)
# 反向生成URL
reverse_url = request.versioning_scheme.reverse(''test'', request=request)
print(reverse_url)
return Response(''GET请求,响应内容'')
def post(self, request, *args, **kwargs):
return Response(''POST请求,响应内容'')
def put(self, request, *args, **kwargs):
return Response(''PUT请求,响应内容'')

c. 基于 accept 请求头方式
如:Accept: application/json; version=1.0

REST_FRAMEWORK = {
''DEFAULT_VERSION'': ''v1'', # 默认版本
''ALLOWED_VERSIONS'': [''v1'', ''v2''], # 允许的版本
''VERSION_PARAM'': ''version'' # URL中获取值的key
}

from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r''^test/'', TestView.as_view(), name=''test''),
]


#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import AcceptHeaderVersioning
class TestView(APIView):
versioning_class = AcceptHeaderVersioning
def get(self, request, *args, **kwargs):
# 获取版本 HTTP_ACCEPT头
print(request.version)
# 获取版本管理的类
print(request.versioning_scheme)
# 反向生成URL
reverse_url = request.versioning_scheme.reverse(''test'', request=request)
print(reverse_url)
return Response(''GET请求,响应内容'')
def post(self, request, *args, **kwargs):
return Response(''POST请求,响应内容'')
def put(self, request, *args, **kwargs):
return Response(''PUT请求,响应内容'')

d. 基于主机名方法
如:v1.example.com

ALLOWED_HOSTS = [''*'']
REST_FRAMEWORK = {
''DEFAULT_VERSION'': ''v1'', # 默认版本
''ALLOWED_VERSIONS'': [''v1'', ''v2''], # 允许的版本
''VERSION_PARAM'': ''version'' # URL中获取值的key
}

from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r''^test/'', TestView.as_view(), name=''test''),
]


#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import HostNameVersioning
class TestView(APIView):
versioning_class = HostNameVersioning
def get(self, request, *args, **kwargs):
# 获取版本
print(request.version)
# 获取版本管理的类
print(request.versioning_scheme)
# 反向生成URL
reverse_url = request.versioning_scheme.reverse(''test'', request=request)
print(reverse_url)
return Response(''GET请求,响应内容'')
def post(self, request, *args, **kwargs):
return Response(''POST请求,响应内容'')
def put(self, request, *args, **kwargs):
return Response(''PUT请求,响应内容'')

e. 基于django路由系统的namespace
如:example.com/v1/users/

REST_FRAMEWORK = {
''DEFAULT_VERSION'': ''v1'', # 默认版本
''ALLOWED_VERSIONS'': [''v1'', ''v2''], # 允许的版本
''VERSION_PARAM'': ''version'' # URL中获取值的key
}


from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r''^v1/'', ([
url(r''test/'', TestView.as_view(), name=''test''),
], None, ''v1'')),
url(r''^v2/'', ([
url(r''test/'', TestView.as_view(), name=''test''),
], None, ''v2'')),
]



#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import NamespaceVersioning
class TestView(APIView):
versioning_class = NamespaceVersioning
def get(self, request, *args, **kwargs):
# 获取版本
print(request.version)
# 获取版本管理的类
print(request.versioning_scheme)
# 反向生成URL
reverse_url = request.versioning_scheme.reverse(''test'', request=request)
print(reverse_url)
return Response(''GET请求,响应内容'')
def post(self, request, *args, **kwargs):
return Response(''POST请求,响应内容'')
def put(self, request, *args, **kwargs):
return Response(''PUT请求,响应内容'')

f. 全局使用

REST_FRAMEWORK = {
''DEFAULT_VERSIONING_CLASS'':"rest_framework.versioning.URLPathVersioning",
''DEFAULT_VERSION'': ''v1'',
''ALLOWED_VERSIONS'': [''v1'', ''v2''],
''VERSION_PARAM'': ''version''
}
5. 解析器(parser)
根据请求头 content-type 选择对应的解析器就请求体内容进行处理。
a. 仅处理请求头content-type为application/json的请求体

from django.conf.urls import url, include
from web.views.s5_parser import TestView
urlpatterns = [
url(r''test/'', TestView.as_view(), name=''test''),
]


#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import JSONParser
class TestView(APIView):
parser_classes = [JSONParser, ]
def post(self, request, *args, **kwargs):
print(request.content_type)
# 获取请求的值,并使用对应的JSONParser进行处理
print(request.data)
# application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
print(request.POST)
print(request.FILES)
return Response(''POST请求,响应内容'')
def put(self, request, *args, **kwargs):
return Response(''PUT请求,响应内容'')

b. 仅处理请求头content-type为application/x-www-form-urlencoded 的请求体

from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r''test/'', TestView.as_view(), name=''test''),
]


#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import FormParser
class TestView(APIView):
parser_classes = [FormParser, ]
def post(self, request, *args, **kwargs):
print(request.content_type)
# 获取请求的值,并使用对应的JSONParser进行处理
print(request.data)
# application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
print(request.POST)
print(request.FILES)
return Response(''POST请求,响应内容'')
def put(self, request, *args, **kwargs):
return Response(''PUT请求,响应内容'')

c. 仅处理请求头content-type为multipart/form-data的请求体

from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r''test/'', TestView.as_view(), name=''test''),
]


#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import MultiPartParser
class TestView(APIView):
parser_classes = [MultiPartParser, ]
def post(self, request, *args, **kwargs):
print(request.content_type)
# 获取请求的值,并使用对应的JSONParser进行处理
print(request.data)
# application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
print(request.POST)
print(request.FILES)
return Response(''POST请求,响应内容'')
def put(self, request, *args, **kwargs):
return Response(''PUT请求,响应内容'')



<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://127.0.0.1:8000/test/" method="post" enctype="multipart/form-data">
<input type="text" name="user" />
<input type="file" name="img">
<input type="submit" value="提交">
</form>
</body>
</html>

d. 仅上传文件

from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r''test/(?P<filename>[^/]+)'', TestView.as_view(), name=''test''),
]


#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import FileUploadParser
class TestView(APIView):
parser_classes = [FileUploadParser, ]
def post(self, request, filename, *args, **kwargs):
print(filename)
print(request.content_type)
# 获取请求的值,并使用对应的JSONParser进行处理
print(request.data)
# application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
print(request.POST)
print(request.FILES)
return Response(''POST请求,响应内容'')
def put(self, request, *args, **kwargs):
return Response(''PUT请求,响应内容'')



<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://127.0.0.1:8000/test/f1.numbers" method="post" enctype="multipart/form-data">
<input type="text" name="user" />
<input type="file" name="img">
<input type="submit" value="提交">
</form>
</body>
</html>

e. 同时多个Parser
当同时使用多个parser时,rest framework会根据请求头content-type自动进行比对,并使用对应parser

from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r''test/'', TestView.as_view(), name=''test''),
]


#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import JSONParser, FormParser, MultiPartParser
class TestView(APIView):
parser_classes = [JSONParser, FormParser, MultiPartParser, ]
def post(self, request, *args, **kwargs):
print(request.content_type)
# 获取请求的值,并使用对应的JSONParser进行处理
print(request.data)
# application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
print(request.POST)
print(request.FILES)
return Response(''POST请求,响应内容'')
def put(self, request, *args, **kwargs):
return Response(''PUT请求,响应内容'')

f. 全局使用


REST_FRAMEWORK = {
''DEFAULT_PARSER_CLASSES'':[
''rest_framework.parsers.JSONParser''
''rest_framework.parsers.FormParser''
''rest_framework.parsers.MultiPartParser''
]
}


from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r''test/'', TestView.as_view(), name=''test''),
]


#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
class TestView(APIView):
def post(self, request, *args, **kwargs):
print(request.content_type)
# 获取请求的值,并使用对应的JSONParser进行处理
print(request.data)
# application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
print(request.POST)
print(request.FILES)
return Response(''POST请求,响应内容'')
def put(self, request, *args, **kwargs):
return Response(''PUT请求,响应内容'')

注意:个别特殊的值可以通过Django的request对象 request._request 来进行获取
6. 序列化
序列化用于对用户请求数据进行验证和数据进行序列化。
a. 自定义字段

from django.conf.urls import url, include
from web.views.s6_serializers import TestView
urlpatterns = [
url(r''test/'', TestView.as_view(), name=''test''),
]


#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from .. import models
class PasswordValidator(object):
def __init__(self, base):
self.base = base
def __call__(self, value):
if value != self.base:
message = ''This field must be %s.'' % self.base
raise serializers.ValidationError(message)
def set_context(self, serializer_field):
"""
This hook is called by the serializer instance,
prior to the validation call being made.
"""
# 执行验证之前调用,serializer_fields是当前字段对象
pass
class UserSerializer(serializers.Serializer):
ut_title = serializers.CharField(source=''ut.title'')
user = serializers.CharField(min_length=6)
pwd = serializers.CharField(error_messages={''required'': ''密码不能为空''}, validators=[PasswordValidator(''666'')])
class TestView(APIView):
def get(self, request, *args, **kwargs):
# 序列化,将数据库查询字段序列化为字典
data_list = models.UserInfo.objects.all()
ser = UserSerializer(instance=data_list, many=True)
# 或
# obj = models.UserInfo.objects.all().first()
# ser = UserSerializer(instance=obj, many=False)
return Response(ser.data)
def post(self, request, *args, **kwargs):
# 验证,对请求发来的数据进行验证
ser = UserSerializer(data=request.data)
if ser.is_valid():
print(ser.validated_data)
else:
print(ser.errors)
return Response(''POST请求,响应内容'')

b. 基于Model自动生成字段

from django.conf.urls import url, include
from web.views.s6_serializers import TestView
urlpatterns = [
url(r''test/'', TestView.as_view(), name=''test''),
]


#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from .. import models
class PasswordValidator(object):
def __init__(self, base):
self.base = str(base)
def __call__(self, value):
if value != self.base:
message = ''This field must be %s.'' % self.base
raise serializers.ValidationError(message)
def set_context(self, serializer_field):
"""
This hook is called by the serializer instance,
prior to the validation call being made.
"""
# 执行验证之前调用,serializer_fields是当前字段对象
pass
class ModelUserSerializer(serializers.ModelSerializer):
user = serializers.CharField(max_length=32)
class Meta:
model = models.UserInfo
fields = "__all__"
# fields = [''user'', ''pwd'', ''ut'']
depth = 2
extra_kwargs = {''user'': {''min_length'': 6}, ''pwd'': {''validators'': [PasswordValidator(666), ]}}
# read_only_fields = [''user'']
class TestView(APIView):
def get(self, request, *args, **kwargs):
# 序列化,将数据库查询字段序列化为字典
data_list = models.UserInfo.objects.all()
ser = ModelUserSerializer(instance=data_list, many=True)
# 或
# obj = models.UserInfo.objects.all().first()
# ser = UserSerializer(instance=obj, many=False)
return Response(ser.data)
def post(self, request, *args, **kwargs):
# 验证,对请求发来的数据进行验证
print(request.data)
ser = ModelUserSerializer(data=request.data)
if ser.is_valid():
print(ser.validated_data)
else:
print(ser.errors)
return Response(''POST请求,响应内容'')

c. 生成URL


from django.conf.urls import url, include
from web.views.s6_serializers import TestView
urlpatterns = [
url(r''test/'', TestView.as_view(), name=''test''),
url(r''detail/(?P<pk>\d+)/'', TestView.as_view(), name=''detail''),
]



#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from .. import models
class PasswordValidator(object):
def __init__(self, base):
self.base = str(base)
def __call__(self, value):
if value != self.base:
message = ''This field must be %s.'' % self.base
raise serializers.ValidationError(message)
def set_context(self, serializer_field):
"""
This hook is called by the serializer instance,
prior to the validation call being made.
"""
# 执行验证之前调用,serializer_fields是当前字段对象
pass
class ModelUserSerializer(serializers.ModelSerializer):
ut = serializers.HyperlinkedIdentityField(view_name=''detail'')
class Meta:
model = models.UserInfo
fields = "__all__"
extra_kwargs = {
''user'': {''min_length'': 6},
''pwd'': {''validators'': [PasswordValidator(666),]},
}
class TestView(APIView):
def get(self, request, *args, **kwargs):
# 序列化,将数据库查询字段序列化为字典
data_list = models.UserInfo.objects.all()
ser = ModelUserSerializer(instance=data_list, many=True, context={''request'': request})
# 或
# obj = models.UserInfo.objects.all().first()
# ser = UserSerializer(instance=obj, many=False)
return Response(ser.data)
def post(self, request, *args, **kwargs):
# 验证,对请求发来的数据进行验证
print(request.data)
ser = ModelUserSerializer(data=request.data)
if ser.is_valid():
print(ser.validated_data)
else:
print(ser.errors)
return Response(''POST请求,响应内容'')

7. 分页
a. 根据页码进行分页


from django.conf.urls import url, include
from rest_framework import routers
from web.views import s9_pagination
urlpatterns = [
url(r''^test/'', s9_pagination.UserViewSet.as_view()),
]



#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework import serializers
from .. import models
from rest_framework.pagination import PageNumberPagination
class StandardResultsSetPagination(PageNumberPagination):
# 默认每页显示的数据条数
page_size = 1
# 获取URL参数中设置的每页显示数据条数
page_size_query_param = ''page_size''
# 获取URL参数中传入的页码key
page_query_param = ''page''
# 最大支持的每页显示的数据条数
max_page_size = 1
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class UserViewSet(APIView):
def get(self, request, *args, **kwargs):
user_list = models.UserInfo.objects.all().order_by(''-id'')
# 实例化分页对象,获取数据库中的分页数据
paginator = StandardResultsSetPagination()
page_user_list = paginator.paginate_queryset(user_list, self.request, view=self)
# 序列化对象
serializer = UserSerializer(page_user_list, many=True)
# 生成分页和数据
response = paginator.get_paginated_response(serializer.data)
return response

b. 位置和个数进行分页

from django.conf.urls import url, include
from web.views import s9_pagination
urlpatterns = [
url(r''^test/'', s9_pagination.UserViewSet.as_view()),
]


#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework import serializers
from .. import models
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination
class StandardResultsSetPagination(LimitOffsetPagination):
# 默认每页显示的数据条数
default_limit = 10
# URL中传入的显示数据条数的参数
limit_query_param = ''limit''
# URL中传入的数据位置的参数
offset_query_param = ''offset''
# 最大每页显得条数
max_limit = None
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class UserViewSet(APIView):
def get(self, request, *args, **kwargs):
user_list = models.UserInfo.objects.all().order_by(''-id'')
# 实例化分页对象,获取数据库中的分页数据
paginator = StandardResultsSetPagination()
page_user_list = paginator.paginate_queryset(user_list, self.request, view=self)
# 序列化对象
serializer = UserSerializer(page_user_list, many=True)
# 生成分页和数据
response = paginator.get_paginated_response(serializer.data)
return response

c. 游标分页

from django.conf.urls import url, include
from web.views import s9_pagination
urlpatterns = [
url(r''^test/'', s9_pagination.UserViewSet.as_view()),
]


#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework import serializers
from .. import models
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination
class StandardResultsSetPagination(CursorPagination):
# URL传入的游标参数
cursor_query_param = ''cursor''
# 默认每页显示的数据条数
page_size = 2
# URL传入的每页显示条数的参数
page_size_query_param = ''page_size''
# 每页显示数据最大条数
max_page_size = 1000
# 根据ID从大到小排列
ordering = "id"
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class UserViewSet(APIView):
def get(self, request, *args, **kwargs):
user_list = models.UserInfo.objects.all().order_by(''-id'')
# 实例化分页对象,获取数据库中的分页数据
paginator = StandardResultsSetPagination()
page_user_list = paginator.paginate_queryset(user_list, self.request, view=self)
# 序列化对象
serializer = UserSerializer(page_user_list, many=True)
# 生成分页和数据
response = paginator.get_paginated_response(serializer.data)
return response

8. 路由系统
a. 自定义路由


from django.conf.urls import url, include
from web.views import s11_render
urlpatterns = [
url(r''^test/$'', s11_render.TestView.as_view()),
url(r''^test\.(?P<format>[a-z0-9]+)$'', s11_render.TestView.as_view()),
url(r''^test/(?P<pk>[^/.]+)/$'', s11_render.TestView.as_view()),
url(r''^test/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)$'', s11_render.TestView.as_view())
]



from rest_framework.views import APIView
from rest_framework.response import Response
from .. import models
class TestView(APIView):
def get(self, request, *args, **kwargs):
print(kwargs)
print(self.renderer_classes)
return Response(''...'')

b. 半自动路由


from django.conf.urls import url, include
from web.views import s10_generic
urlpatterns = [
url(r''^test/$'', s10_generic.UserViewSet.as_view({''get'': ''list'', ''post'': ''create''})),
url(r''^test/(?P<pk>\d+)/$'', s10_generic.UserViewSet.as_view(
{''get'': ''retrieve'', ''put'': ''update'', ''patch'': ''partial_update'', ''delete'': ''destroy''})),
]



#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.viewsets import ModelViewSet
from rest_framework import serializers
from .. import models
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class UserViewSet(ModelViewSet):
queryset = models.UserInfo.objects.all()
serializer_class = UserSerializer

c. 全自动路由


from django.conf.urls import url, include
from rest_framework import routers
from web.views import s10_generic
router = routers.DefaultRouter()
router.register(r''users'', s10_generic.UserViewSet)
urlpatterns = [
url(r''^'', include(router.urls)),
]



from rest_framework.viewsets import ModelViewSet
from rest_framework import serializers
from .. import models
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class UserViewSet(ModelViewSet):
queryset = models.UserInfo.objects.all()
serializer_class = UserSerializer

9. 视图
a. GenericViewSet


from django.conf.urls import url, include
from web.views.s7_viewset import TestView
urlpatterns = [
url(r''test/'', TestView.as_view({''get'':''list''}), name=''test''),
url(r''detail/(?P<pk>\d+)/'', TestView.as_view({''get'':''list''}), name=''xxxx''),
]



#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework import viewsets
from rest_framework.response import Response
class TestView(viewsets.GenericViewSet):
def list(self, request, *args, **kwargs):
return Response(''...'')
def add(self, request, *args, **kwargs):
pass
def delete(self, request, *args, **kwargs):
pass
def edit(self, request, *args, **kwargs):
pass

b. ModelViewSet(自定义URL)


from django.conf.urls import url, include
from web.views import s10_generic
urlpatterns = [
url(r''^test/$'', s10_generic.UserViewSet.as_view({''get'': ''list'', ''post'': ''create''})),
url(r''^test/(?P<pk>\d+)/$'', s10_generic.UserViewSet.as_view(
{''get'': ''retrieve'', ''put'': ''update'', ''patch'': ''partial_update'', ''delete'': ''destroy''})),
]



#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.viewsets import ModelViewSet
from rest_framework import serializers
from .. import models
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class UserViewSet(ModelViewSet):
queryset = models.UserInfo.objects.all()
serializer_class = UserSerializer

c. ModelViewSet(rest framework路由)


from django.conf.urls import url, include
from rest_framework import routers
from app01 import views
router = routers.DefaultRouter()
router.register(r''users'', views.UserViewSet)
router.register(r''groups'', views.GroupViewSet)
# Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API.
urlpatterns = [
url(r''^'', include(router.urls)),
]



from rest_framework import viewsets
from rest_framework import serializers
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = models.User
fields = (''url'', ''username'', ''email'', ''groups'')
class GroupSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = models.Group
fields = (''url'', ''name'')
class UserViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = User.objects.all().order_by(''-date_joined'')
serializer_class = UserSerializer
class GroupViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows groups to be viewed or edited.
"""
queryset = Group.objects.all()
serializer_class = GroupSerializer

10. 渲染器
根据 用户请求URL 或 用户可接受的类型,筛选出合适的 渲染组件。
用户请求URL:
- http://127.0.0.1:8000/test/?format=json
- http://127.0.0.1:8000/test.json
用户请求头:
- Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
a. json
访问URL:
- 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.views import s11_render
urlpatterns = [
url(r''^test/$'', s11_render.TestView.as_view()),
url(r''^test\.(?P<format>[a-z0-9]+)'', s11_render.TestView.as_view()),
]



#!/usr/bin/env python
# -*- coding:utf-8 -*-
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):
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)

b. 表格
访问URL:
- http://127.0.0.1:8000/test/?format=admin
- http://127.0.0.1:8000/test.admin
- http://127.0.0.1:8000/test/


#!/usr/bin/env python
# -*- coding:utf-8 -*-
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)

c. Form表单
访问URL:
- http://127.0.0.1:8000/test/?format=form
- http://127.0.0.1:8000/test.form
- http://127.0.0.1:8000/test/


#!/usr/bin/env python
# -*- coding:utf-8 -*-
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 AdminRenderer
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)

d. 自定义显示模板
访问URL:
- http://127.0.0.1:8000/test/?format=html
- http://127.0.0.1:8000/test.html
- http://127.0.0.1:8000/test/


from django.conf.urls import url, include
from web.views import s11_render
urlpatterns = [
url(r''^test/$'', s11_render.TestView.as_view()),
url(r''^test\.(?P<format>[a-z0-9]+)'', s11_render.TestView.as_view()),
]



#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from rest_framework.renderers import TemplateHTMLRenderer
from .. import models
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class TestView(APIView):
renderer_classes = [TemplateHTMLRenderer, ]
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'')



<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ user }}
{{ pwd }}
{{ ut }}
</body>
</html>

e. 浏览器格式API+JSON
访问URL:
- http://127.0.0.1:8000/test/?format=api
- http://127.0.0.1:8000/test.api
- http://127.0.0.1:8000/test/


#!/usr/bin/env python
# -*- coding:utf-8 -*-
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__"
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'')

注意:如果同时多个存在时,自动根据URL后缀来选择渲染器。
今天关于为整个结果集向Django Rest Framework结果添加额外的数据和实现对一个结果集进行分组和汇总的介绍到此结束,谢谢您的阅读,有关1 Django REST Framework 开发 ---- 原生 Django View 热身、Django - rest - framework - 下、django - 插件 django REST framework, 返回序列化的数据、Django Rest Framework等更多相关知识的信息可以在本站进行查询。
本文标签: