rest_framework
一.解析器组件(parser)
1.编程:数据结构和算法的结合
2.restful规范
定义:url唯一定位资源,http请求方式区分用户行为
(1)接口设计规范
(2)返回数据规范
(3)错误消息规范
3.classbasedview原码
4.restframework下的APIView的请求流程和原码
下载:pip install djangorestframework
引入:from rest_framework import APIView
APIView的原码:
5.POSTMAN工具的使用
能够发各种方式的请求并对请求头的数据进行修改且对结果进行格式化的工具
6.DRF解析器(parser)的请求流程和原码
解析器:Django只能解析urlencoded格式的数据,通过解析器 可以解析各种数据类型(json)的数据
(1)使用方式
导入模块
from rest_framework.views import APIView
(2)继承
(3)
(4)使用
原码:
APIView中的
二.序列化组件
0.原始序列化方法
model对象=>字典
from django.forms.models import model_to_dict
model_to_dict方法:将model对象转换成字典
0.djaogo的自带的序列化方法
from django.core import serializers
ret=serializers.serialize("json",queryset)
得到的ret就是序列化后的结果
rest_framework的serializer使用方法(五个接口)
1.get接口设计(查看多条数据)
(1)Serializer,类似于Form
#1.导入模块
from rest_framework.views import APIView
from rest_framework import serializers
#使返回的数据能够格式化
#浏览器上也能够使用rest_framework组件
#***前提是settings中的INSTALLED_APPS要配置该组件***
from rest_framework.response import Response from django.shortcuts import HttpResponse
from app01.models import * #2.写一个类继承serializers.Serializer
class BookSerializer(serializers.Serializer):
title=serializers.CharField(max_length=32)
price=serializers.CharField(max_length=32)
#对于一对多的字段,用source来决定返回给前端的内容
publish=serializers.CharField(source="publish.name")
#对于多对多的字段,用钩子函数来编辑返回给前端的内容
authors=serializers.SerializerMethodField()
#钩子函数的名字是get+字段的名字
def get_authors(self,book_obj):
s=""
for obj in book_obj.authors.all():
s=s+obj.name
return s class BookView(APIView):
def get(self,request):
book_list=Book.objects.all()
#多个对象时
#many为True表示多个对象,默认为false,位false时可以省略不写
bs=BookSerializer(book_list,many=True)
#单个对象时
#bs=BookSerializer(book_obj)
return Response(bs.data) # 返回的是[{},{}]的形式
由于使用的是Response返回的数据,访问该路径时,能够得到rest_framework组件为我们提供的页面
在访问的路径后加上?format=json,得到的是数据部分
(2)ModelSerializer,类似于ModelForm
#1.导入模块
from rest_framework.views import APIView
from rest_framework import serializers
#使返回的数据能够格式化
#浏览器上也能够使用rest_framework组件
#***前提是settings中的INSTALLED_APPS要配置该组件***
from rest_framework.response import Response from django.shortcuts import HttpResponse
from app01.models import * #2.写一个类继承serializers.ModelSerializer
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model=Book
fields="__all__"
#自定义的字段
publish=serializers.CharField(source="publish.name")
authors=serializers.SerializerMethodField()
def get_authors(self,book_obj):
s=""
for obj in book_obj.authors.all():
s=s+obj.name
return s class BookView(APIView):
def get(self,request):
book_list=Book.objects.all()
#多个对象时
#many为True表示多个对象,默认为false,位false时可以省略不写
bs=BookModelSerializer(book_list,many=True)
#单个对象时
#bs=BookSerializer(book_obj)
return Response(bs.data) # 返回的是[{},{}]的形式
访问时得到的页面
2.post接口设计(添加操作)
from django.shortcuts import HttpResponse
from app01.models import *
from rest_framework.views import APIView
from rest_framework import serializers
#使返回的数据能够格式化
#浏览器上也能够使用rest_framework组件
#前提是settings中的INSTALLED_APPS要配置该组件
from rest_framework.response import Response #1.编写继承ModelSerializer的类
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model=Book
fields="__all__"
publish=serializers.CharField(source="publish.pk")
# authors=serializers.SerializerMethodField() def get_authors(self,book_obj):
s=""
for obj in book_obj.authors.all():
s=s+obj.name
return s
#2.对于一对多的字段,ModelSerializer中的create方法不支持source,重写create方法
def create(self,validated_data):
book_obj=Book.objects.create(title=validated_data["title"],price=validated_data["price"],publish_id=validated_data["publish"]["pk"])
book_obj.authors.add(*validated_data["authors"])
return book_obj class BookView(APIView):
def post(self,request):
bs=BookModelSerializer(data=request.data)
#3.通过实例对象的is_valid()方法,对请求数据的合法性进行校验,有instance就是update,没有就是create
if bs.is_valid():
#4.调用save()方法,将数据插入数据库
#会执行create方法
bs.save()
return Response(bs.data)
else:
#5.数据不合格返回错误信息
return Response(bs.errors)
3.单条数据接口(查询单个数据)
(1)url设计
urlpatterns = [
path('admin/', admin.site.urls),
re_path('book/$', views.BookView.as_view()),
re_path('book/(\d+)/$', views.BookDetailView.as_view()),
]
(2)视图设计
from django.shortcuts import HttpResponse
from app01.models import *
from rest_framework.views import APIView
from rest_framework import serializers
from rest_framework.response import Response class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model=Book
fields="__all__"
publish=serializers.CharField(source="publish.pk")
# authors=serializers.SerializerMethodField() def get_authors(self,book_obj):
s=""
for obj in book_obj.authors.all():
s=s+obj.name
return s
def create(self,validated_data):
book_obj=Book.objects.create(title=validated_data["title"],price=validated_data["price"],publish_id=validated_data["publish"]["pk"])
book_obj.authors.add(*validated_data["authors"])
return book_obj class BookDetailView(APIView):
def get(self,request,id):
book=Book.objects.filter(pk=id).first()
bs=BookModelSerializer(book)
return Response(bs.data)
(3)返回数据
4.put接口设计(更新操作)
from django.shortcuts import HttpResponse
from app01.models import *
from rest_framework.views import APIView
from rest_framework import serializers
from rest_framework.response import Response class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model=Book
fields="__all__" class BookDetailView(APIView):
def put(self,request,id):
book = Book.objects.filter(pk=id).first()
bs=BookModelSerializer(book,data=request.data)
if bs.is_valid():
#此时执行的不是create方法,是update方法
bs.save()
return Response(bs.data)
else:
return Response(bs.errors)
5.delete接口设计
from django.shortcuts import HttpResponse
from app01.models import *
from rest_framework.views import APIView
from rest_framework import serializers
from rest_framework.response import Response class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model=Book
fields="__all__" class BookDetailView(APIView):
def delete(self,request,id):
Book.objects.filter(pk=id).delete()
return Response()
超链接API:Hyperlinked
实现效果:
建立向Book表的BookView,BookDetailView一样的Publish表的两个视图类
class PublishView(APIView):
def get(self,request):
book_list=Publish.objects.all()
print(book_list)
bs=PublishModelSerializer(book_list,many=True)
print(bs)
print(bs.data)
return Response(bs.data) # [{},{}]的形式
def post(self,request):
print(request.data) bs=PublishModelSerializer(data=request.data)
if bs.is_valid():
#会执行create方法
print(111)
bs.save()
print(bs.data)
return Response(bs.data)
else:
return Response(bs.errors)
class PublishDetailView(APIView):
def get(self,request,id):
book=Publish.objects.filter(pk=id).first()
bs=PublishModelSerializer(book)
print(book)
print(bs)
print('-------',bs.data)
return Response(bs.data) def put(self,request,id):
book = Publish.objects.filter(pk=id).first()
bs=PublishModelSerializer(book,data=request.data)
if bs.is_valid():
bs.save()
return Response(bs.data)
else:
return Response(bs.errors) def delete(self,request,id):
Publish.objects.filter(pk=id).delete()
return Response()
视图类中需要的PublishModelSerializer
class PublishModelSerializer(serializers.ModelSerializer):
class Meta:
model=Publish
fields="__all__"
修改访问BookView时的publish的显示方式
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model=Book
fields="__all__"
publish=serializers.HyperlinkedIdentityField(
view_name="publish_detail",#路径的别名
lookup_field="publish_id",
lookup_url_kwarg="id"#路径中用到的动态匹配的数据
)
设置BookModelSerializer需要的view_name,lookup_url_kwarg
urlpatterns = [
path('admin/', admin.site.urls),
# path('publish/', views.PublishView.as_view()),
path('publishnew/', views.PublishnNewView.as_view(),name="publishnew"),
re_path('book/$', views.BookView.as_view(),name="book"),
re_path('publish/$', views.PublishView.as_view(),name="publish"),
re_path('book/(\d+)/$', views.BookDetailView.as_view(),name="bookdetail"),
re_path('publish/(?P<id>\d+)/$', views.PublishDetailView.as_view(),name="publish_detail"),
]
用了Hyperlinked,以后调用时,都要加上context={'request': request}
三.视图组件
1.mixin类编写视图
CreateModelMixin 添加
DestroyModelMixin 删除
ListModelMixin 查多个
RetrieveModelMixin 查单个
UpdateModelMixin 更新
ListModelMixin部分原码
class ListModelMixin(object):
"""
List a queryset.
"""
def list(self, request, *args, **kwargs):
#获取queryset
queryset = self.filter_queryset(self.get_queryset()) page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
#序列化
serializer = self.get_serializer(queryset, many=True)
#返回.data数据
return Response(serializer.data)
CreateModelMixin部分原码
class ListModelMixin(object):
"""
List a queryset.
"""
def list(self, request, *args, **kwargs):
#获取queryset
queryset = self.filter_queryset(self.get_queryset()) page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
#序列化
serializer = self.get_serializer(queryset, many=True)
#返回.data数据
return Response(serializer.data)
CreateModelMixin部分原码
class CreateModelMixin(object):
"""
Create a model instance.
"""
def create(self, request, *args, **kwargs):
#获取ModelSerializer的实例对象
serializer = self.get_serializer(data=request.data)
#判断是否合法,成功了继续走,错误了抛错
serializer.is_valid(raise_exception=True)
#合法后执行save方法
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) def perform_create(self, serializer):
serializer.save() def get_success_headers(self, data):
try:
return {'Location': str(data[api_settings.URL_FIELD_NAME])}
except (TypeError, KeyError):
return {}
使用
在urls.py中
urlpatterns = [
path('admin/', admin.site.urls),
re_path('author/$', views.AuthorView.as_view(),name="author"),
#***此处正则表达式的有名分组一定要命名为pk***
re_path('author/(?P<pk>\d+)/$', views.AuthorDetailView.as_view(),name="author_detail"),
]
在视图中
#1.导入需要的类
from rest_framework import mixins
from rest_framework import generics #GenericAPIView继承了APIView
#定义的类除了要继承mixins下的类以外,还要继承GenericAPIView类
class AuthorView(mixins.ListModelMixin,mixins.CreateModelMixin,generics.GenericAPIView):
#以下两个配置信息的名字是固定的
#queryset此次表示处理的数据
queryset=Author.objects.all()
#serializers表示用到的序列化组件
serializer_class=AuthorModelSerializer
def get(self, request, *args, **kwargs):
#ListModelMixin类中的方法
return self.list(self, request, *args, **kwargs)
def post(self, request, *args, **kwargs):
#CreateModelMixin中的方法
return self.create(self, request, *args, **kwargs) class AuthorDetailView(mixins.RetrieveModelMixin,mixins.DestroyModelMixin,mixins.UpdateModelMixin,generics.GenericAPIView):
queryset = Author.objects.all()
serializer_class = AuthorModelSerializer
def get(self, request,pk, *args, **kwargs):
return self.retrieve(self, request,pk, *args, **kwargs)
def put(self, request,id, *args, **kwargs):
return self.update(self, request,id, *args, **kwargs)
def delete(self, request,id, *args, **kwargs):
return self.destroy(self, request,id, *args, **kwargs)
get请求得到的数据
[
{
"nid": 1,
"name": "徐志摩",
"age": 25
},
{
"nid": 2,
"name": "鲁迅",
"age": 25
}
]
2.使用通用的基于类的视图
ListCreateAPIView原码部分
##ListCreateAPIView固定继承了mixins.ListModelMixin,mixins.CreateModelMixin,GenericAPIView
class ListCreateAPIView(mixins.ListModelMixin,
mixins.CreateModelMixin,
GenericAPIView):
#贴心到连get和post方法都写了
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs) def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
RetrieveUpdateDestroyAPIView原码部分(与ListCreateAPIView原理相同)
class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
GenericAPIView): 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 patch(self, request, *args, **kwargs):
return self.partial_update(request, *args, **kwargs) def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
使用
在urls.py中
urlpatterns = [
path('admin/', admin.site.urls),
re_path('author/$', views.AuthorView.as_view(),name="author"),
#***此处正则表达式的有名分组一定要命名为pk***
re_path('author/(?P<pk>\d+)/$', views.AuthorDetailView.as_view(),name="author_detail"),
]
在视图中
from rest_framework import generics class AuthorView(generics.ListCreateAPIView):
queryset=Author.objects.all()
serializer_class=AuthorModelSerializer class AuthorDetailView(generics.RetrieveUpdateDestroyAPIView):
queryset = Author.objects.all()
serializer_class = AuthorModelSerializer
3.viewsets.ModelViewSet
使用
在urls.py中
urlpatterns = [
path('admin/', admin.site.urls),
#利用as_view的参数,规定什么请求方式用什么方法处理
re_path(r'^books/$', views.AuthorViewSet.as_view({"get": "list", "post": "create"}), name="book_list"),
re_path(r'^books/(?P<pk>\d+)$', views.AuthorViewSet.as_view({
'get': 'retrieve',
'put': 'update',
'patch': 'partial_update',
'delete': 'destroy'
}), name="book_detail"),
]
在视图中
from rest_framework import viewsets
class AuthorViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = AuthorModelSerializer
四.认证组件
1.使用方式
单个认证
(1)定义一个认证类
class UserAuth():
#此方法原码中会用到,一定要写
def authenticate_header(self,request):
pass
def authenticate(self,request):
token=request.GET.get("token")
token_obj = UserToken.objects.filter(token=token).first()
if not token_obj:
raise APIException("验证失败!")
return (token_obj.user, token_obj)
或者用BaseAuthentication类来代替authenticate_header方法
from rest_framework.authentication import BaseAuthentication
class UserAuth(BaseAuthentication):
def authenticate(self,request):
token=request.GET.get("token")
token_obj = UserToken.objects.filter(token=token).first()
if not token_obj:
raise APIException("验证失败!")
return (token_obj.user, token_obj)
(2)在需要认证的数据接口里面指定认证类
class AuthorViewSet(viewsets.ModelViewSet):
***authentication_classes = [UserAuth,]***
queryset = Author.objects.all()
serializer_class = AuthorModelSerializer
(3)前提:要在登录时注入token
def get_random_str():
import uuid
random_str=str(uuid.uuid4()).replace("-","")
return random_str class LoginView(APIView):
def post(self,request):
user_name=request.data.get("user_name")
password=request.data.get("password")
user_obj=User.objects.filter(user_name=user_name,password=password).first()
res={}
if not user_obj:
res["state"]=1001
res["meg"]='用户名或秘密错误'
else:
token=get_random_str()
print(token)
UserToken.objects.update_or_create(user=user_obj, defaults={"token": token})
res["state"]=1000
res["meg"]='登录成功'
return JsonResponse(res)
全局认证
(1)将UserAuth单放在一个文件中
utiles中
from app01.models import *
from rest_framework.exceptions import APIException
class UserAuth():
def authenticate_header(self,request):
pass
def authenticate(self,request):
token=request.GET.get("token")
token_obj = UserToken.objects.filter(token=token).first()
if not token_obj:
raise APIException("验证失败!")
return (token_obj.user, token_obj)
(2)在配置文件中添加配置
REST_FRAMEWORK={
"DEFAULT_AUTHENTICATION_CLASSES":("app01.utiles.UserAuth",)
}
2.原码剖析
class APIView(View):
#***1执行as_view方法
def as_view(cls, **initkwargs):
if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet):
def force_evaluation():
raise RuntimeError(
'Do not evaluate the `.queryset` attribute directly, '
'as the result will be cached and reused between requests. '
'Use `.all()` or call `.get_queryset()` instead.'
)
cls.queryset._fetch_all = force_evaluation
#***2.继承父类的as_view方法并执行
view = super(APIView, cls).as_view(**initkwargs)
view.cls = cls
view.initkwargs = initkwargs
return csrf_exempt(view) ########################################################### #***3.续
def dispatch(self, request, *args, **kwargs):
"""
`.dispatch()` is pretty much the same as Django's regular dispatch,
but with extra hooks for startup, finalize, and exception handling.
"""
self.args = args
self.kwargs = kwargs
#***4.执行initialize_request方法
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate? try:
#***8.执行inital方法
self.initial(request, *args, **kwargs) # Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed response = handler(request, *args, **kwargs) except Exception as exc:
response = self.handle_exception(exc) self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response ########################################################### #***4.续
def initialize_request(self, request, *args, **kwargs):
"""
Returns the initial request object.
"""
parser_context = self.get_parser_context(request)
#***5.实例化Request对象
return Request(
request,
parsers=self.get_parsers(),
#***6.执行get_authenticators方法
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
) ###########################################################
#***6.续
def get_authenticators(self):
#***7.authentication_classes为自定义的类中的字段:[UserAuth,]
return [auth() for auth in self.authentication_classes] ###########################################################
#***8.续
def initial(self, request, *args, **kwargs):
self.format_kwarg = self.get_format_suffix(**kwargs)
neg = self.perform_content_negotiation(request)
request.accepted_renderer, request.accepted_media_type = neg version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme
#***9.用户认证方法
self.perform_authentication(request)
self.check_permissions(request)
self.check_throttles(request) ########################################################### #***9.续
def perform_authentication(self, request):
#***10.执行Request类下的user方法
request.user
class View:
def as_view(cls, **initkwargs): for key in initkwargs:
if key in cls.http_method_names:
raise TypeError("You tried to pass in the %s method name as a "
"keyword argument to %s(). Don't do that."
% (key, cls.__name__))
if not hasattr(cls, key):
raise TypeError("%s() received an invalid keyword %r. as_view "
"only accepts arguments that are already "
"attributes of the class." % (cls.__name__, key)) def view(request, *args, **kwargs):
self = cls(**initkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
#***3.执行APIView中的dispatch方法
return self.dispatch(request, *args, **kwargs)
view.view_class = cls
view.view_initkwargs = initkwargs
update_wrapper(view, cls, updated=())
update_wrapper(view, cls.dispatch, assigned=())
return view
自定义
#***7.续
class AuthorViewSet(viewsets.ModelViewSet):
authentication_classes = [UserAuth,]
queryset = Author.objects.all()
serializer_class = AuthorModelSerializer
Request
#***10.续
def user(self):
if not hasattr(self, '_user'):
with wrap_attributeerrors():
#***11.执行_authenticate方法
self._authenticate()
#***15.返回14步骤的当前登录对象
return self._user ############################################################# #***11.续
def _authenticate(self):
#***12.self.authenticators为7步骤的结果[UserAuth(),]
for authenticator in self.authenticators:
try:
#***13.执行自定义的认证类下的authenticate方法
user_auth_tuple = authenticator.authenticate(self)
#***14.续
#如果用户的token值错误抛错,在此抛错
except exceptions.APIException:
self._not_authenticated()
raise if user_auth_tuple is not None:
self._authenticator = authenticator
#如果用户的token值正确, self.user为当前登录对象
self.user, self.auth = user_auth_tuple
return self._not_authenticated()
class UserAuth():
def authenticate_header(self,request):
pass
#***13.续
def authenticate(self,request):
token=request.GET.get("token")
token_obj = UserToken.objects.filter(token=token).first()
#***14.分情况讨论
if not token_obj:
#如果用户的token值错误,抛错
raise APIException("验证失败!")
#如果用户带有正确的token值
return (token_obj.user, token_obj)
1.一次性从前端获取多条数据
2.给 name属性赋值,就会执行 第二个方法
五.权限组件
1.使用方式
单个权限
(1)定义权限类
class UserPerms():
#方法名称一定叫has_permission
#自定义错误信息
def has_permission(self,request,view):
if request.user.user_type == 3:
return True
else:
return False
(2)指定权限验证类
class AuthorViewSet(viewsets.ModelViewSet):
authentication_classes = [UserAuth,]
#使用 方式与认证相同
permission_classes = [UserPerms,]
queryset = Author.objects.all()
serializer_class = AuthorModelSerializer
可以指定多个认证类,如果返回数据,应在最后一个类中返回数据
(3)前提也是登录时要注入token
全局权限
REST_FRAMEWORK={
"DEFAULT_PERMISSION_CLASSES":["app01.utiles.UserPerms",]
}
2.原码剖析
从APIView的dispatch方法开始剖析
APIView
#***1.执行dispatch方法def dispatch(self, request, *args, **kwargs): self.args = args
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate? try:
#***2.执行initial方法(有续)
self.initial(request, *args, **kwargs) # Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed response = handler(request, *args, **kwargs) except Exception as exc:
response = self.handle_exception(exc) self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response ##############################################################333# #***2.续
def initial(self, request, *args, **kwargs): self.format_kwarg = self.get_format_suffix(**kwargs) # Perform content negotiation and store the accepted info on the request
neg = self.perform_content_negotiation(request)
request.accepted_renderer, request.accepted_media_type = neg # Determine the API version, if versioning is in use.
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme # Ensure that the incoming request is permitted
self.perform_authentication(request)
#***3.执行check_permissions权限方法(有续)
self.check_permissions(request)
self.check_throttles(request) ###########################################################3 #***3.续
def check_permissions(self, request):
#***4.执行self.get_permissions方法(有续)
for permission in self.get_permissions():
#***6.执行自定义的has_permission方法
if not permission.has_permission(request, self):
#***7.执行permission_denied(有续)
self.permission_denied(
request, message=getattr(permission, 'message', None)
)
#########################################################
#***4.续
def get_permissions(self):
#***5.self.permission_classes位自定义的属性(有续)
return [permission() for permission in self.permission_classes]
#########################################################
#***7.续
def permission_denied(self, request, message=None):
#False抛错,True不管
if request.authenticators and not request.successful_authenticator:
raise exceptions.NotAuthenticated()
raise exceptions.PermissionDenied(detail=message)
class AuthorViewSet(viewsets.ModelViewSet):
authentication_classes = [UserAuth,]
#***5.续
permission_classes = [UserPerms]
queryset = Author.objects.all()
serializer_class = AuthorModelSerializer
class UserPerms():
#***6.续
message="您没有查看该数据的权限" #自定义错误信息
def has_permission(self,request,view):
if request.user.user_type == 3:
return True
else:
return False
#符合条件返回True,不符合条件返回False
六.频率组件
1.使用方式
定义频率类
class VisitRateThrottle():
def allow_request(request,self,view):
if 通过:
return True#通过
else:
return False#不通过,频率超了
指定频率类
class AuthorViewSet(viewsets.ModelViewSet):
#指定频率类
throttle_classes = [VisitRateThrottle,]
queryset = Author.objects.all()
serializer_class = AuthorModelSerializer
2.限制每分钟 的访问次数
from rest_framework.throttling import BaseThrottle
VISIT_RECORD={}
class VisitRateThrottle(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])
class AuthorViewSet(viewsets.ModelViewSet):
#指定频率类
throttle_classes = [VisitRateThrottle,]
queryset = Author.objects.all()
serializer_class = AuthorModelSerializer
3.使用DRF的简单频率控制来控制用户访问频率(局部)
定义频率类
from rest_framework.throttling import SimpleRateThrottle
class RateThrottle(SimpleRateThrottle):
rate = "5/m"
def get_cache_key(self, request, view):
return self.get_ident(request)
class AuthorViewSet(viewsets.ModelViewSet):
#指定频率类
throttle_classes = [RateThrottle,]
queryset = Author.objects.all()
serializer_class = AuthorModelSerializer
4.使用DRF的简单频率控制来控制用户访问频率(全局)
定义频率类
from rest_framework.throttling import SimpleRateThrottle
class RateThrottle(SimpleRateThrottle):
# 指定访问频率
scope = 'visit_rate'
# 指定通过什么方式来区分用户
def get_cache_key(self, request, view):
return self.get_ident(request)
在settings配置文件中
REST_FRAMEWORK = {
"DEFAULT_THROTTLE_CLASSES": ('app01.throttle.RateThrottle',),
"DEFAULT_THROTTLE_RATES": {
"visit_rate": "5/m"
}
}
七.url注册器
使用方式
#导入模块
from django.urls import path,re_path,include
from app01 import views
from rest_framework import routers
#生成一个注册器的实例对象
routers=routers.DefaultRouter()
#注册url接口,第一个参数为路径部分,第二个参数为视图类
routers.register(r"author",views.AuthorViewSet)
#生成url
urlpatterns = [
path('admin/', admin.site.urls),
#
re_path(r"^",include(routers.urls))
]
前提:只针对viewsets.ModelViewSet的情况
class AuthorViewSet(viewsets.ModelViewSet):
queryset = Author.objects.all()
serializer_class = AuthorModelSerializer
八.响应器
#引入模块
from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
class AuthorViewSet(viewsets.ModelViewSet):
#指定
renderer_classes = [JSONRenderer,]
queryset = Author.objects.all()
serializer_class = AuthorModelSerializer
pagination_class = MyPagenation
效果:以前浏览器在访问时,会得到rest_framework为我们提供的页面,
使用JSONRenderer后浏览器只能得到json数据,没有压页面
九.分页器
PageNumberPagination使用方式1
#导入模块
from rest_framework.pagination import PageNumberPagination
class BookView(APIView):
def get(self,request):
#获取queryset
book_list=Book.objects.all()
#实例化PageNumberPagination
paginater=PageNumberPagination()
#调用paginate_queryset方法
paged_books=paginater.paginate_queryset(book_list,request,self)
#将分页后的数据传入BookModelSerializer
bs=BookModelSerializer(paged_books,many=True,context={'request': request})
return Response(bs.data)
注意在settings中配置REST_FRAMEWORK
REST_FRAMEWORK = {
#原码中会到setting中找PAGE_SIZE,如果找不到会报错
"PAGE_SIZE":4,
}
方式一中,所有用PageNumberPagination类来分页的数据都会因为全局中的"PAGE_SIZE":4,每页只能分四个
PageNumberPagination使用方式2
自定义一个分页器,继承PageNumberPagination,不同的数据可以每页显示不同的个数
自定义分页器类并继承PageNumberPagination
from rest_framework.pagination import PageNumberPagination
class MyPagenation(PageNumberPagination):
page_size = 3 #每页显示多少条数据
page_query_param = 'page' #get查询是?后面的查询条件
page_size_query_param = 'size' #?page=2&size=10,第二页临时改成每页显示十条
max_page_size = 5 #每页最多显示的数据数
使用自定义的分页器类
class BookView(APIView):
def get(self,request):
#获取queryset
book_list=Book.objects.all()
#MyPagenation
paginater=MyPagenation()
#调用paginate_queryset方法
paged_books=paginater.paginate_queryset(book_list,request,self)
#将分页后的数据传入BookModelSerializer
bs=BookModelSerializer(paged_books,many=True,context={'request': request})
return Response(bs.data)
偏移分页 LimitOffsetPagination
from rest_framework.pagination import LimitOffsetPagination class MyLimitOffsetPagination(LimitOffsetPagination):
default_limit = 3 #每页显示几条数据 class BookView(APIView):
def get(self,request):
#获取queryset
book_list=Book.objects.all()
#实例化MyLimitOffsetPagination
paginater=MyLimitOffsetPagination()
#调用paginate_queryset方法
paged_books=paginater.paginate_queryset(book_list,request,self)
#将分页后的数据传入BookModelSerializer
bs=BookModelSerializer(paged_books,many=True,context={'request': request})
return Response(bs.data)
访问http://127.0.0.1:8000/book/?limit=3&offset=2,表示临时显示三条数据,偏移两条数据
viewsets.ModelViewSet接口数据的分页
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination
#自定义分页类
class MyPagenation(PageNumberPagination):
page_size = 1
page_query_param = 'p'
page_size_query_param = 'size'
max_page_size = 5 class Aut horViewSet(viewsets.ModelViewSet):
queryset = Author.objects.all()
serializer_class = AuthorModelSerializer
*****为自定义的ModelViewSet类添加pagination_class字段,绑定分页器类
pagination_class = MyPagenation
rest_framework的更多相关文章
- Django rest_framework 实用技巧
前言: 最近工作中需要用到Django rest_framework框架做API, 边学边写,记录了一些实际工作中需要用到的功能,不是很全也不系统,以后需要什么功能可以在这查询. 后续还会更新其它的用 ...
- django rest_framework--入门教程3
rest_framwork 之post 与put rest_framwork可以接受post与put delete get请求,可以对资源进行刚CRUD,以一个DEMO为例, 1.先在VIEW里定义一 ...
- django rest_framework--入门教程2
接上文 这里先写一个GET请求的 1.先在VIEW里定义一个方法 代码如下: @api_view(['GET', 'POST']) def book_request(request): if requ ...
- django rest_framework
环境 django 1.6,rest_framework 3.3 ubuntu采用pip安装的rest_framework 按照例子一步步做下来 运行 提示filters.py第119行有错误form ...
- REST_FRAMEWORK加深记忆-极致抽象,极致完结
余下的就是静心看官方文档了. 这个是最抽象的了. urls.py """tutorial URL Configuration The `urlpatterns` list ...
- REST_FRAMEWORK加深记忆-加了API_ROOT及超链接的CASE
urls.py from django.conf.urls import url from rest_framework.urlpatterns import format_suffix_patter ...
- REST_FRAMEWORK加深记忆-加了用户登陆认证,自定义权限的API接口
哈哈,终于快结束了.. urls.py from django.conf.urls import include, url from django.contrib import admin urlpa ...
- REST_FRAMEWORK加深记忆-三种CLASS VIEW的进化史
一层一层的封装,又能到底层,就会有全局感啦... from rest_framework import status from rest_framework.response import Respo ...
- REST_FRAMEWORK加深记忆-第二次练习官方文档2
优化前和优化后的代码,融在一起,能看看进化的过程. MODELS.PY from django.db import models from pygments.lexers import get_all ...
- REST_FRAMEWORK加深记忆-第二次练习官方文档
我想,其它几个基于PYTHON的REST API模块概念都差不多吧. 先深入搞定这个吧. 前几次练习完了有一些印象,并且在工作中实践过一个,现在多弄几次,玩熟悉点. Serializers.py __ ...
随机推荐
- 华为软件开发云(DevCloud):免费可商用的项目管理工具
在软件开发技术和理念层出不穷的今天,如何更快的适应变化的环境,更好的满足客户的需求,已经成为决定从小到大各种规模企业能否活下去的关键. 天下武功唯快不破,在当今大环境中更是如此,微服务,敏捷开发,新的 ...
- 轻松掌握XMLHttpRequest对象
XmlHttp是什么? 最通用的定义为:XmlHttp是一套可以在Javascript.VbScript.Jscript等脚本语言中通过http协议传送或从接收XML及其他数据的一套API.XmlHt ...
- 设计模式在JDK中的应用
在JDK(Java Development Kit)类库中,开发人员使用了大量设计模式. 创建型模式: (1) 抽象工厂模式(Abstract Factory) • java.util.Calenda ...
- Troubleshooting routing topology based on a reference topology
In one embodiment, a computing device (e.g., border router or network management server) transmits a ...
- Indexing Sensor Data
In particular embodiments, a method includes, from an indexer in a sensor network, accessing a set o ...
- javascript的回调函数 同步 异步
后一个任务等待前一个任务结束再执行.程序执行顺序与任务排列顺序一致的,同步的. 参考: http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%B ...
- [ACM] POJ 2689 Prime Distance (筛选范围大素数)
Prime Distance Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 12811 Accepted: 3420 D ...
- python爬虫 BeautifulSoup
简单来说,Beautiful Soup是python的一个库,最主要的功能是从网页抓取数据. Beautiful Soup自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码. Bea ...
- 手把手教你安装QT集成开发环境(操作系统为ubuntu10.04,需要先安装build-essential和libncurses5-dev)
在安装QT集成开发工具包之前需要先安装build-essential和libncurses5-dev这两个开发工具和库,libncurses5-dev库是一个在Linux/Unix下广泛应用的图形函数 ...
- ISO9000 质量管理和质量保证系列国际标准
(一)ISO9000认证的背景国际标准化组织(ISO)是世界上最主要的非政府间国际标准化机构,成立于二次世界大战以后,总部位于瑞士日内瓦.该组织的目的是在世界范围内促进标准化及有关工作的发展,以利于国 ...