笔记来源课程:https://pythonav.com/index/
APIView 的特点并且可以通过request获取参数 特点 1.继承自View 2.提供了自己的request对象 3.提供了自己的response对象 4.并且提供了认证,权限,限流等功能 定义序列化器: 1.定义类,继承自Serializer 2.和模型类,字段名字一样 3.和模型类,字段类型一样 4.和模型类,字段选项一样 label 字段说明 read_only = True 只读意思就是只进行序列化不进行反序列化所以反序列化时可以不用传
反序列化: 校验: 1.字段类型校验 2.字段选项校验 3.单字段校验(方法) 4.多字段校验(方法) 5.自定义校验(方法)
入库: 1.创建新对象 2.更新对象
pip3 install djangorestframework
使用注册app
INSTALLED_APPS
= [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework'
]
写路由
from django
.conf
.urls
import url
from django
.contrib
import admin
from api
import views
urlpatterns
= [
url
(r
'^drf/info/', views
.DrfInfoView
.as_view
()),
]
写视图
from rest_framework
.views
import APIView
from rest_framework
.response
import Response
class DrfInfoView(APIView
):
def get(self
,request
,*args
,**kwargs
):
return Response
()
depth = 1但是这样会拿全部信息 source 在自定义字段时表示来源 自定义字段钩子方法: x1 = serializers.SerializerMethodField() 必须要有此方法 def get_x1(self,obj): obj表示当前对象 return obj.title
serializers
.CharField
(source
=get_status_display
)
required
=false表示你在添加数据也就是反序列化的时候不需要填这个数据
(只写
)
read_only
= true 表示序列化也就是模型转json的时候使用
什么是restful规范
是一套规则,用于程序之间进行数据交换的约定。
他规定了一些协议,对我们感受最直接的的是,以前写增删改查需要写
4个接口,restful规范的就是
1个接口,根据method的不同做不同的操作,比如:get
/post
/delete
/put
/patch
/delete
.
初次之外,resetful规范还规定了:
数据传输通过json
什么是drf
drf是一个基于django开发的组件,本质是一个django的app。
drf可以办我们快速开发出一个遵循restful规范的程序。
写程序的潜规则:约束
class Base(object):
def f1(self
):
raise NotImplementedError
('asdfasdfasdfasdf')
class Foo(Base
):
def f1(self
):
print(123)
obj
= Foo
()
obj
.f1
()
分页(版本一)
配置 settings.pyREST_FRAMEWORK = {
"PAGE_SIZE":2
}
在视图的列表页面
from rest_framework
.pagination
import PageNumberPagination
from rest_framework
import serializers
class PageArticleSerializer(serializers
.ModelSerializer
):
class Meta:
model
= models
.Article
fields
= "__all__"
class PageArticleView(APIView
):
def get(self
,request
,*args
,**kwargs
):
queryset
= models
.Article
.objects
.all()
"""
# 分页对象
page_object = PageNumberPagination()
# 调用 分页对象.paginate_queryset方法进行分页,得到的结果是分页之后的数据
# result就是分完页的一部分数据
result = page_object.paginate_queryset(queryset,request,self)
# 序列化分页之后的数据
ser = PageArticleSerializer(instance=result,many=True)
return Response(ser.data)
"""
"""
page_object = PageNumberPagination()
result = page_object.paginate_queryset(queryset, request, self)
ser = PageArticleSerializer(instance=result, many=True)
return page_object.get_paginated_response(ser.data)
"""
page_object
= PageNumberPagination
()
result
= page_object
.paginate_queryset
(queryset
, request
, self
)
ser
= PageArticleSerializer
(instance
=result
, many
=True)
return Response
({'count':page_object
.page
.paginator
.count
,'result':ser
.data
})
LimitOffsetPagination
from rest_framework
.pagination
import PageNumberPagination
from rest_framework
.pagination
import LimitOffsetPagination
from rest_framework
import serializers
class PageArticleSerializer(serializers
.ModelSerializer
):
class Meta:
model
= models
.Article
fields
= "__all__"
class HulaLimitOffsetPagination(LimitOffsetPagination
):
max_limit
= 2
class PageArticleView(APIView
):
def get(self
,request
,*args
,**kwargs
):
queryset
= models
.Article
.objects
.all()
page_object
= HulaLimitOffsetPagination
()
result
= page_object
.paginate_queryset
(queryset
, request
, self
)
ser
= PageArticleSerializer
(instance
=result
, many
=True)
return Response
(ser
.data
)
url
(r
'^page/view/article/$', views
.PageViewArticleView
.as_view
()),
from rest_framework
.generics
import ListAPIView
class NewFilterBacke(BaseFilterBackend
):
def filter_queryset(self
, request
, queryset
, view
):
val
= request
.query_params
.get
('cagetory')
return queryset
.filter(cagetory_id
=val
)
class PageViewArticleSerializer(serializers
.ModelSerializer
):
class Meta:
model
= models
.Article
fields
= "__all__"
class PageViewArticleView(ListAPIView
):
queryset
= "模型数据"
filter_backends
= [NewFilterBacke
, ]
serializer_class
= "序列化器"
pagination_class
= PageNumberPagination
REST_FRAMEWORK
= {
"PAGE_SIZE":2,
"DEFAULT_PAGINATION_CLASS":"rest_framework.pagination.PageNumberPagination"
}
可以重写一些方法
class TageView(ListAPIView
, CreateAPIView
):
queryset
= "数据"
serializer_class
= "序列化器"
def get_serializer_class(self
):
if self
.request
.method
== "GET":
return "序列化器"
elif self
.request
.method
== 'POST':
return "序列化器"
def perfiom_create(self
,serializer
):
serializer
.save
(author
=1)
继承关系:重点
class View(object):
def dispatch(self
):
print(123)
class APIView(View
):
version_class
= None
parser_class
= None
permision_classes
= []
def dispatch(self
):
self
.initial
()
method
= getattr(self
,"get")
return method
()
def initial(self
):
self
.version_class
().xxx
self
.parser_class
()
for item
in self
.permision_classes
:
item
()
class GenericAPIView(APIView
):
queryset
= None
serilizer_class
= None
def get_queryset(self
):
return self
.queryset
def get_serilizer(self
,*args
,**kwargs
):
cls
= self
.get_serilizer_class
()
return cls
(*args
,**kwargs
)
def get_serilizer_class(self
):
return self
.serilizer_class
class ListModelMixin(object):
def list(self
):
queryset
= self
.get_queryset
()
ser
= self
.get_serilizer
(queryset
,may
=True)
return Reponse
(ser
.data
)
class ListAPIView(ListModelMixin
,GenericAPIView
):
def get(self
):
return self
.list(.....)
class Tage(ListAPIView
):
queryset
= models
.Users
.objects
.all()
serilizer_class
= "序列化器"
version_class
= URLPathClass
parser_class
= JSONclass
permission_classes
= [FOO
,Bar
]
obj
= Tage
()
x
= obj
.dispatch
()
请求的封装
class HttpRequest(object):
def __init__(self
):
pass
@propery
def GET(self
):
pass
@propery
def POST(self
):
pass
@propery
def body(self
):
pass
class Request(object):
def __init__(self
,request
):
self
._request
= request
def data(self
):
if content
-type == "application/json"
reutrn json
.loads
(self
._request
.body
.decode
('urf-8'))
elif content
-type == "x-www-...":
return self
._request
.POST
def query_params(self
):
return self
._reqeust
.GET
req
= HttpRequest
()
request
= Request
(req
)
request
.data
request
.query_prams
request
._request
.GET
request
._request
.POST
request
._request
.body
- 视图关系
class View(object):
@classonlymethod
def as_view(cls
, **initkwargs
):
def view(request
, *args
, **kwargs
):
return self
.dispatch
(request
, *args
, **kwargs
)
return view
class APIView(View
):
@
classmethod
def as_view(cls
, **initkwargs
):
view
= super().as_view
(**initkwargs
)
return csrf_exempt
(view
)
def dispatch(self
, request
, *args
, **kwargs
):
request
= self
.initialize_request
(request
, *args
, **kwargs
)
self
.request
= request
self
.initial
(request
, *args
, **kwargs
)
handler
= getattr(self
, request
.method
.lower
())
response
= handler
(request
, *args
, **kwargs
)
return self
.response
class OrderView(APIView
):
def get(self
,request
,*args
,**kwargs
):
return Response
('1312')
版本
from django
.conf
.urls
import url
,include
from django
.contrib
import admin
from . import views
urlpatterns
= [
url
(r
'^order/$', views
.OrderView
.as_view
()),
]
from rest_framework
.views
import APIView
from rest_framework
.response
import Response
from rest_framework
.request
import Request
class OrderView(APIView
):
def get(self
,request
,*args
,**kwargs
):
print(request
.version
)
print(request
.versioning_scheme
)
return Response
('...')
def post(self
,request
,*args
,**kwargs
):
return Response
('post')
源码流程:
class APIView(View
):
versioning_class
= api_settings
.DEFAULT_VERSIONING_CLASS
def dispatch(self
, request
, *args
, **kwargs
):
"""
request,是django的request,它的内部有:request.GET/request.POST/request.method
args,kwargs是在路由中匹配到的参数,如:
url(r'^order/(\d+)/(?P<version>\w+)/$', views.OrderView.as_view()),
http://www.xxx.com/order/1/v2/
"""
self
.args
= args
self
.kwargs
= kwargs
"""
request = 生成了一个新的request对象,此对象的内部封装了一些值。
request = Request(request)
- 内部封装了 _request = 老的request
"""
request
= self
.initialize_request
(request
, *args
, **kwargs
)
self
.request
= request
self
.headers
= self
.default_response_headers
try:
self
.initial
(request
, *args
, **kwargs
)
执行视图函数。。
def initial(self
, request
, *args
, **kwargs
):
version
, scheme
= self
.determine_version
(request
, *args
, **kwargs
)
request
.version
, request
.versioning_scheme
= version
, scheme
...
def determine_version(self
, request
, *args
, **kwargs
):
if self
.versioning_class
is None:
return (None, None)
scheme
= self
.versioning_class
()
return (scheme
.determine_version
(request
, *args
, **kwargs
), scheme
)
class OrderView(APIView
):
versioning_class
= URLPathVersioning
def get(self
,request
,*args
,**kwargs
):
print(request
.version
)
print(request
.versioning_scheme
)
return Response
('...')
def post(self
,request
,*args
,**kwargs
):
return Response
('post')
class URLPathVersioning(BaseVersioning
):
"""
urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/users/$', users_list, name='users-list'),
]
"""
invalid_version_message
= _
('Invalid version in URL path.')
def determine_version(self
, request
, *args
, **kwargs
):
version
= kwargs
.get
(self
.version_param
, self
.default_version
)
if version
is None:
version
= self
.default_version
if not self
.is_allowed_version
(version
):
raise exceptions
.NotFound
(self
.invalid_version_message
)
return version
使用(局部)
url中写version
url
(r
'^(?P<version>[v1|v2]+)/users/$', users_list
, name
='users-list'),
from rest_framework
.views
import APIView
from rest_framework
.response
import Response
from rest_framework
.request
import Request
from rest_framework
.versioning
import URLPathVersioning
class OrderView(APIView
):
versioning_class
= URLPathVersioning
def get(self
,request
,*args
,**kwargs
):
print(request
.version
)
print(request
.versioning_scheme
)
return Response
('...')
def post(self
,request
,*args
,**kwargs
):
return Response
('post')
REST_FRAMEWORK
= {
"PAGE_SIZE":2,
"DEFAULT_PAGINATION_CLASS":"rest_framework.pagination.PageNumberPagination",
"ALLOWED_VERSIONS":['v1','v2'],
'VERSION_PARAM':'version'
}
使用(全局)推荐
url中写version
url
(r
'^(?P<version>[v1|v2]+)/users/$', users_list
, name
='users-list'),
url
(r
'^(?P<version>\w+)/users/$', users_list
, name
='users-list'),
在视图中应用
from rest_framework
.views
import APIView
from rest_framework
.response
import Response
from rest_framework
.request
import Request
from rest_framework
.versioning
import URLPathVersioning
class OrderView(APIView
):
def get(self
,request
,*args
,**kwargs
):
print(request
.version
)
print(request
.versioning_scheme
)
return Response
('...')
def post(self
,request
,*args
,**kwargs
):
return Response
('post')
REST_FRAMEWORK
= {
"PAGE_SIZE":2,
"DEFAULT_PAGINATION_CLASS":"rest_framework.pagination.PageNumberPagination",
"DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
"ALLOWED_VERSIONS":['v1','v2'],
'VERSION_PARAM':'version'
}
认证
from django
.conf
.urls
import url
,include
from django
.contrib
import admin
from . import views
urlpatterns
= [
url
(r
'^login/$', views
.LoginView
.as_view
()),
url
(r
'^order/$', views
.OrderView
.as_view
()),
url
(r
'^user/$', views
.UserView
.as_view
()),
]
import uuid
from django
.shortcuts
import render
from django
.views
import View
from django
.views
.decorators
.csrf
import csrf_exempt
from django
.utils
.decorators
import method_decorator
from rest_framework
.versioning
import URLPathVersioning
from rest_framework
.views
import APIView
from rest_framework
.response
import Response
from . import models
class LoginView(APIView
):
def post(self
,request
,*args
,**kwargs
):
user_object
= models
.UserInfo
.objects
.filter(**request
.data
).first
()
if not user_object
:
return Response
('登录失败')
random_string
= str(uuid
.uuid4
())
user_object
.token
= random_string
user_object
.save
()
return Response
(random_string
)
class MyAuthentication:
def authenticate(self
, request
):
"""
Authenticate the request and return a two-tuple of (user, token).
"""
token
= request
.query_params
.get
('token')
user_object
= models
.UserInfo
.objects
.filter(token
=token
).first
()
if user_object
:
return (user_object
,token
)
return (None,None)
class OrderView(APIView
):
authentication_classes
= [MyAuthentication
, ]
def get(self
,request
,*args
,**kwargs
):
print(request
.user
)
print(request
.auth
)
return Response
('order')
class UserView(APIView
):
authentication_classes
= [MyAuthentication
,]
def get(self
,request
,*args
,**kwargs
):
print(request
.user
)
print(request
.auth
)
return Response
('user')
源码分析
class Request:
def __init__(self
, request
,authenticators
=None):
self
._request
= request
self
.authenticators
= authenticators
or ()
@
property
def user(self
):
"""
Returns the user associated with the current request, as authenticated
by the authentication classes provided to the request.
"""
if not hasattr(self
, '_user'):
with wrap_attributeerrors
():
self
._authenticate
()
return self
._user
def _authenticate(self
):
"""
Attempt to authenticate the request using each authentication instance
in turn.
"""
for authenticator
in self
.authenticators
:
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
._not_authenticated
()
@user
.setter
def user(self
, value
):
"""
Sets the user on the current request. This is necessary to maintain
compatibility with django.contrib.auth where the user property is
set in the login and logout functions.
Note that we also set the user on Django's underlying `HttpRequest`
instance, ensuring that it is available to any middleware in the stack.
"""
self
._user
= value
self
._request
.user
= value
class APIView(View
):
authentication_classes
= api_settings
.DEFAULT_AUTHENTICATION_CLASSES
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.
"""
"""
request,是django的request,它的内部有:request.GET/request.POST/request.method
args,kwargs是在路由中匹配到的参数,如:
url(r'^order/(\d+)/(?P<version>\w+)/$', views.OrderView.as_view()),
http://www.xxx.com/order/1/v2/
"""
self
.args
= args
self
.kwargs
= kwargs
"""
request = 生成了一个新的request对象,此对象的内部封装了一些值。
request = Request(request)
- 内部封装了 _request = 老的request
- 内部封装了 authenticators = [MyAuthentication(), ]
"""
request
= self
.initialize_request
(request
, *args
, **kwargs
)
self
.request
= request
def initialize_request(self
, request
, *args
, **kwargs
):
"""
Returns the initial request object.
"""
parser_context
= self
.get_parser_context
(request
)
return Request
(
request
,
parsers
=self
.get_parsers
(),
authenticators
=self
.get_authenticators
(),
negotiator
=self
.get_content_negotiator
(),
parser_context
=parser_context
)
def get_authenticators(self
):
"""
Instantiates and returns the list of authenticators that this view can use.
"""
return [ auth
() for auth
in self
.authentication_classes
]
class LoginView(APIView
):
authentication_classes
= []
def post(self
,request
,*args
,**kwargs
):
user_object
= models
.UserInfo
.objects
.filter(**request
.data
).first
()
if not user_object
:
return Response
('登录失败')
random_string
= str(uuid
.uuid4
())
user_object
.token
= random_string
user_object
.save
()
return Response
(random_string
)
class OrderView(APIView
):
def get(self
,request
,*args
,**kwargs
):
print(request
.user
)
print(request
.auth
)
if request
.user
:
return Response
('order')
return Response
('滚')
当用户发来请求时,找到认证的所有类并实例化成为对象列表,然后将对象列表封装到新的request对> 象中。 以后在视同中调用request.user 在内部会循环认证的对象列表,并执行每个对象的authenticate方法,该方法用于认证,他会返回两个值分别会赋值给 request.user/request.auth
权限
from rest_framework
.permissions
import BasePermission
from rest_framework
import exceptions
class MyPermission(BasePermission
):
message
= {'code': 10001, 'error': '你没权限'}
def has_permission(self
, request
, view
):
"""
Return `True` if permission is granted, `False` otherwise.
"""
if request
.user
:
return True
return False
def has_object_permission(self
, request
, view
, obj
):
"""
Return `True` if permission is granted, `False` otherwise.
"""
return False
class OrderView(APIView
):
permission_classes
= [MyPermission
,]
def get(self
,request
,*args
,**kwargs
):
return Response
('order')
class UserView(APIView
):
permission_classes
= [MyPermission
, ]
def get(self
,request
,*args
,**kwargs
):
return Response
('user')
REST_FRAMEWORK
= {
"PAGE_SIZE":2,
"DEFAULT_PAGINATION_CLASS":"rest_framework.pagination.PageNumberPagination",
"DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
"ALLOWED_VERSIONS":['v1','v2'],
'VERSION_PARAM':'version',
"DEFAULT_AUTHENTICATION_CLASSES":["kka.auth.TokenAuthentication",]
}
源码分析
class APIView(View
):
permission_classes
= api_settings
.DEFAULT_PERMISSION_CLASSES
def dispatch(self
, request
, *args
, **kwargs
):
封装request对象
self
.initial
(request
, *args
, **kwargs
)
通过反射执行视图中的方法
def initial(self
, request
, *args
, **kwargs
):
版本的处理
self
.perform_authentication
(request
)
self
.check_permissions
(request
)
self
.check_throttles
(request
)
def perform_authentication(self
, request
):
request
.user
def check_permissions(self
, request
):
for permission
in self
.get_permissions
():
if not permission
.has_permission
(request
, self
):
self
.permission_denied
(request
, message
=getattr(permission
, 'message', None))
def permission_denied(self
, request
, message
=None):
if request
.authenticators
and not request
.successful_authenticator
:
raise exceptions
.NotAuthenticated
()
raise exceptions
.PermissionDenied
(detail
=message
)
def get_permissions(self
):
return [permission
() for permission
in self
.permission_classes
]
class UserView(APIView
):
permission_classes
= [MyPermission
, ]
def get(self
,request
,*args
,**kwargs
):
return Response
('user')