参考资料
http://www.yuan316.com/post/DRF/
全站最牛逼的DRF(Django-restframework),没有之一!
序章、创建django项目
项目每次处相当于执行命令:django-admin startproject xxx
应用名称处:python manage.py startap
此外创建了虚拟环境、自动安装了django等
安装相应得包
pip install pymysql
pip install djangorestframework -i https://pypi.douban.com/simple
pip install mysqlclient
一、序列化、view 与viewset
一、CBV与FBV
- FBV(Function-Based Views)基于函数的视图
# views.py
from django.shortcuts import HttpResponse
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def book_views(request):
if request.method == "GET":
return HttpResponse("这是get")
if request.method == "POST":
return HttpResponse("这是post")
if request.method == "DELETE":
return HttpResponse("这是delete")
if request.method == "PUT":
return HttpResponse("这是put")
# urls.py
from django.urls import path
from app001 import views
urlpatterns = [
# fbv
path('book/',views.book_views),
]
- CBV(Class-Based Views)基于类的视图
# views.py
from django.shortcuts import HttpResponse
from django.views import View
from django.utils.decorators import method_decorator
@method_decorator(csrf_exempt, name='dispatch') # 类视图禁止crsf
class BookView(View):
def get(self, request):
return HttpResponse("这是get")
def post(self, request):
return HttpResponse("这是post")
def delete(self, request):
return HttpResponse("这是delete")
def put(self, request):
return HttpResponse("这是put")
# urls.py
from django.urls import path
from app001 import views
urlpatterns = [
# cbv
path('book/',views.BookView.as_view())
]
-
注意
1 urls.py 中使用
book/
访问时需要加上/
,否则会转为get
请求
2 访问get
外的其它请求,需要禁用csrf,cbv与fbv禁用方法是不一样的
二、APIView(了解)
在settings.py的INSTALLED_APPS中添加’rest_framework’,
#settings.py
INSTALLED_APPS = [
...
'rest_framework',
]
需要将CBV中的class BookView(View)
变为class BookView(APIView)
导入from rest_framework.views import APIView
即可
# views.py
from rest_framework.views import APIView
from django.shortcuts import HttpResponse
class BookView(APIView):
def get(self, request):
return HttpResponse("这是get")
def post(self, request):
return HttpResponse("这是post")
def delete(self, request):
return HttpResponse("这是delete")
def put(self, request):
return HttpResponse("这是put")
urls.py
都不用改变
# urls.py
from django.urls import path
from app001 import views
urlpatterns = [
# cbv
path('book/',views.BookView.as_view())
]
三、序列化与反序列化(掌握)
序列化与反序列化
后端可能用得时python、java、go等语言数据类型各不相同,那后端怎么给前端传输数据呢 ?
就像你要和阿拉伯人交流、都不会对方国家的语言怎么办?恰好都会英语,用英语作为桥梁
这里采取json作为桥梁;把python数据对象转为json就是序列化、json转为python数据对象就是反序列化
- 1、ModelSerializer
存在Django的模型类使用ModelSerializer
非常方便,优点1 会根据模型类自动生成序列化字段 2 自带create和update方法 - 表模型如下
# models.py
from django.db import models
class Book(models.Model):
# id = models.IntegerField(primary_key=True) 不要定义id 这会自动生成
title = models.CharField(max_length=32, blank=True, null=True, db_comment='书籍名称',verbose_name="书籍名称")
price = models.IntegerField(blank=True, null=True, db_comment='价格',verbose_name='价格')
pub_date = models.DateField(blank=True, null=True, db_comment='出版日期',verbose_name='出版日期')
bread = models.IntegerField(blank=True, null=True, db_comment='阅读量',verbose_name='阅读量')
bcomment = models.IntegerField(blank=True, null=True, db_comment='评论量',verbose_name='评论量')
class Meta:
# 和数据库名称一致,否则会生成appname_book为表名
db_table = 'book'
# managed = False # django 不用管理它,默认True进行管理
- Book表序列化器
class BookSerializers(serializers.ModelSerializer):
date = serializers.DateField(source="pub_date") # 将book中的pub_date 转为接送中的date
class Meta:
model = Book # 指明对应模型名称
# fields和exclude只能同时存在一个
fields = "__all__" # 选取所有的字段
# fields = ["bread","bcomment"] # 选取某些字段
# exclude = ["bread","bcomment"] # 排除某些字段
# extra_kwargs = {
# 'id': {'required': False}, # 将 id 字段设为非必填项
# }
增删改查接口 不需要id的接口 获得所有与新增接口
# views.py
from rest_framework.generics import GenericAPIView # 也可以全部替换成APIView
from rest_framework.response import Response
class BookView(GenericAPIView):
def get(self, request):
# 获取所有书籍
book_list = Book.objects.all()
# 构建序列化对象
resp = BookSerializers(instance=book_list,
many=True) # instance 用来指定要序列化的对象或对象列表。many 默认为 False many=True 返回一个列表;many=Flase返回json对象;用来指示序列化器处理多个对象(列表)而非单个对象。 当处理单个对象时,不需要设置 many=True()
return Response(resp.data) # 将结果转为json
def post(self, request):
req = BookSerializers(data=request.data) # data用于反序列化
# 数据校验
if req.is_valid():
req.save() # 创建数据
return Response(req.data)
else:
return Response(req.errors)
- 需要id的接口获得、删除、修改某条数据
from rest_framework import status
class BookDetailView(GenericAPIView): #
def put(self, request, id):
update_book = Book.objects.get(pk=id)
serializer = BookSerializers(instance=update_book, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors)
def delete(self, request, id):
try:
book = Book.objects.get(pk=id)
book.delete()
return Response({"message":"删除成功!"},status=status.HTTP_200_OK)
except Book.DoesNotExist:
return Response({'error': 'Book not found'}, status=status.HTTP_404_NOT_FOUND)
# update_book = Book.objects.get(pk=id).delete() # 不需要校验
# # if update
# return Response(update_book.data)
def get(self, request, id):
update_book = Book.objects.get(pk=id)
serializer = BookSerializers(instance=update_book, many=False) # many=False获取一条数据
return Response(serializer.data)
- 路由配置如下
# url.py
from django.urls import path,re_path
from drf_demo import views
urlpatterns = [
# cbv
path('book/', views.BookView.as_view()),
re_path('book/(\d+)', views.BookDetailView.as_view()), # 单独一条数据
# re_path(r'^book/(\d+)/$') # 更严格的表达式
]
总结:
1 Response
from rest_framework.response import Response
使用 return Response(resp.data)
将结果转为json
2 序列化器中的 instance、data与many
BookSerializers(instance=book_list,many=True)
2.1 instance
instance用来指示序列化器处理多个对象(列表)而非单个对象。
2.2 many
many 默认为 False
当many=True 返回一个列表;用来指示序列化器处理多个对象(列表)而非单个对象
当many=Flase返回json对象; 当处理单个对象时,不需要设置 many=True()
2.3 data
req = BookSerializers(data=request.data) # data用于反序列化
- instance一般用于
get
、put
请求,从数据库给前端数据涉及读
操作;data
一般用于post
,put
用于写入数据库涉及写
操作
总结
模式 | 初始化方式 | 用途 |
---|---|---|
序列化(输出) | serializer = MySerializer(instance) | 将模型实例转为 JSON 等格式 |
反序列化(输入) | serializer = MySerializer(data=…) | 将输入数据(如 POST 请求)转为 Python 对象并验证 |
四、GenericAPIView (存在 queryset与serializer_class就使用GenericAPIView )(掌握)
具体用法参考 http://www.yuan316.com/post/DRF/
1 代码实现
# views.py
# ========================== 2 queryset与serializer_class 版本 使用 GenericAPIView =============================================
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
class BookView(GenericAPIView):
queryset = Book.objects.all() # 变量名一个字母大小写都不能错 去找 self.queryset
serializer_class = BookSerializers # 变量名一个字母大小写都不能错 去找self.serializer_class
def get(self, request):
# 获取所有书籍
serializer=self.get_serializer(instance=self.get_queryset(),many=True)
return Response(serializer.data)
def post(self,request):
serializer = self.get_serializer(data=request.data)
# 数据校验
if serializer.is_valid():
serializer.save() # 创建数据
return Response(serializer.data)
else:
return Response(serializer.errors)
class BookDetailView(GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializers
def put(self, request, pk):
serializer = self.get_serializer(data=request.data,instance=self.get_object(),many=False) # get_object会过滤单条数据
# update_book = Book.objects.get(pk=id)
# serializer = BookSerializers(instance=update_book, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors)
def get(self,request,pk):
serializer = self.get_serializer(instance=self.get_object(), many=False) # get_object会过滤单条数据
return Response(serializer.data)
def delete(self,request,pk):
self.get_object().delete()
# self.get_object().detete()
return Response({"message":"删除成功!"})
- 路由配置如下
# url.py
from django.urls import path,re_path
from drf_demo import views
urlpatterns = [
# cbv
path('book/', views.BookView.as_view()),
re_path('book/(\d+)', views.BookDetailView.as_view()), # 单独一条数据
# 有名分组 将捕获到的数据使用pk传给视图
re_path('book/(?P<pk>\d+)', views.BookDetailView.as_view()) # 使用GenericAPIView后采取有名分组
]
2 queryset 与 serializer_class 来源
queryset = Book.objects.all()
和serializer_class = BookSerializers
来自哪里?
在GenericAPIView
类变量中存在下面两个变量都是如果最外面的子类不定义会抛出异常的
queryset = None
serializer_class = None
在GenericAPIView
中存在self.get_queryset()
函数
下面的self.queryset
就是你写的 queryset = Book.objects.all()
这是一个QuerySet类型
源码如下
def get_queryset(self):
assert self.queryset is not None, (
"'%s' should either include a `queryset` attribute, "
"or override the `get_queryset()` method."
% self.__class__.__name__
)
queryset = self.queryset
if isinstance(queryset, QuerySet):
# Ensure queryset is re-evaluated on each request.
queryset = queryset.all()
return queryset
-
关于
.all()
queryset = queryset.all()
那不就成了Book.objects.all().all()
了吗?是的,从代码上看确实会变成 Book.objects.all().all(),但 Django 的 ORM 会智能处理这种情况,并不会导致多余的数据库查询。换句话说,.all() 方法是幂等的——无论调用多少次,它的效果都是相同的。
为什么不会产生重复查询?
在 Django 中,.all() 方法的实现非常简单,如果在已有 QuerySet 上再次调用 .all(),它只会返回同一个 QuerySet 对象,并不会创建新的查询或产生额外的数据库开销。
同理可得 serializer_class = BookSerializers
不变
在GenericAPIView
存在下面两个函数
get_serializer_class
只是返回了self.serializer_class
因此不能写错
而get_serializer
看注释即可serializer_class = BookSerializers
def get_serializer(self, *args, **kwargs):
serializer_class = self.get_serializer_class() # serializer_class = self.serializer_class 而 serializer_class = BookSerializers 相当于 serializer_class = BookSerializers
kwargs.setdefault('context', self.get_serializer_context())
return serializer_class(*args, **kwargs) # 相当于BookSerializers(*args, **kwargs) 之前原生用法就是的resp = BookSerializers(instance=book_list,many=True)
def get_serializer_class(self):
assert self.serializer_class is not None, (
"'%s' should either include a `serializer_class` attribute, "
"or override the `get_serializer_class()` method."
% self.__class__.__name__
)
return self.serializer_class
3 如何实现的
调用链为
所有的请求先到 base.py的View.view()因为 GenericAPIView继承APIView,APIView(View)中as_view()存在view = super().as_view() 要去找 base.py的View.view()
大概如下所示
GenericAPIView
=>·APIView
=> APIView(View).as_view()中super().as_view()
=> base.py的View.view()
调用self.dispatch
(明确self是谁非常关键)=> 执行APIView
的dispatch
(存在重写dispatch)请参考13调用规则 2 self的调用=>执行 APIView
的self.initial
(认证、权限、限流组件三件套)=>return get()
- BookView的实例化
View
类中as_view
下的view
代码self = cls(**initkwargs) # BookView()
指出了我们调用的时候是views.BookView.as_view()
其实BookView
就是cls
,cls()
相当于BookView()
可以参考此文章,这里进行的实例化才有了self
from rest_framework.generics import GenericAPIView
class BookView(GenericAPIView)
def get(self, request):
print("get方法已经执行")
return HttpResponse("APIView GET请求...")
def post(self, request):
return HttpResponse("APIView POST请求...")
def delete(self, request):
return HttpResponse("APIView DELETE请求...")
class APIView(View):
def as_view(cls):
view = super().as_view() # # as_view也会访问View.view()
return view
def dispatch(self,request,*args,**kwargs):
# 构建新的request对象
request = self.initialize_request(request, *args, **kwargs)
self.request =request
# 初始化:认证、权限、限流组件三件套
self.initial(request,*args,**kwargs)
# 分发逻辑
handler = getattr(self, request.method.lower())
return handler(request,*args,**kwargs)
class View:
def as_view(cls, **initkwargs):
def view(request, *args, **kwargs):
self = cls(**initkwargs) # BookView()
self.setup(request, *args, **kwargs)
return self.dispatch(request, *args, **kwargs)
"""
path('book/',views.BookView.as_view()) # as_view也会访问View.view()
一旦用户访问book,比如get请求访问/book/
get请求访问 /book/= > view()= > return self.dispatch()=》return get()
"""
五、minin混合类(了解)
# ========================== 3 minin混合类 进一步精简代码 =============================================
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, \
DestroyModelMixin
from rest_framework.response import Response
"""
基于GenericAPIView(因为它有分发方法)结合5个视图扩展类完成基本的5个API接口 这几个接口实现逻辑由源码完成 如self.list(request) 实现了 serializer=self.get_serializer(instance=self.get_queryset(),many=True)h和return Response(serializer.data)
``
ListModelMixin 提供了list方法,获取多条数据
CreateModelMixin 提供了create方法,添加一条数据
RetrieveModelMixin 提供了retrieve方法,获取一条数据 中文名 检索
UpdateModelMixin 提供了update方法,更新一条数据
DestroyModelMixin 提供了destroy方法,删除一条数据
"""
class BookView(ListModelMixin, CreateModelMixin, GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializers
def get(self, request):
# 获取所有书籍
# serializer=self.get_serializer(instance=self.get_queryset(),many=True)
# return Response(serializer.data)
return self.list(request)
def post(self, request):
# serializer = self.get_serializer(data=request.data)
# # 数据校验
# if serializer.is_valid():
# serializer.save() # 创建数据
# return Response(serializer.data)
# else:
# return Response(serializer.errors)
return self.create(request)
class BookDetailView(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializers
def put(self, request, pk):
# serializer = self.get_serializer(data=request.data,instance=self.get_object(),many=False) # get_object会过滤单条数据
#
# # update_book = Book.objects.get(pk=id)
# # serializer = BookSerializers(instance=update_book, data=request.data)
# if serializer.is_valid():
# serializer.save()
# return Response(serializer.data)
# else:
# return Response(serializer.errors)
return self.update(request, pk)
def get(self, request, pk):
# serializer = self.get_serializer(instance=self.get_object(), many=False) # get_object会过滤单条数据
# return Response(serializer.data)
return self.retrieve(request, pk)
def delete(self, request, pk):
self.get_object().delete()
# self.get_object().detete()
# return Response({"message":"删除成功!"})
return self.destroy(request, pk)
- 路由配置如下
# url.py
from django.urls import path,re_path
from drf_demo import views
urlpatterns = [
# cbv
path('book/', views.BookView.as_view()),
# 有名分组 将捕获到的数据使用pk传给视图
re_path('book/(?P<pk>\d+)', views.BookDetailView.as_view()) # 使用GenericAPIView后采取有名分组
]
六、minin混合类 再进一步精简代码(了解)
# ========================== 4 minin混合类 再进一步精简代码 =============================================
"""
主函数没有去继承里面找的 继承实现了各种方法
ListCreateAPIView 实现了get和post APIView是指并继承了GenericAPIView
RetrieveUpdateDestroyAPIView 实现了get、put、delete方法所以下面的都不用写了
其实也有ListAPIView(s实现get方法等单个接口)
"""
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView
class BookView(ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializers
class BookDetailView(RetrieveUpdateDestroyAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializers
- 路由配置如下
# url.py
from django.urls import path,re_path
from drf_demo import views
urlpatterns = [
# cbv
path('book/', views.BookView.as_view()),
# 有名分组 将捕获到的数据使用pk传给视图
re_path('book/(?P<pk>\d+)', views.BookDetailView.as_view()) # 使用GenericAPIView后采取有名分组
]
七、GenericViewSet(常用掌握)
- 实现在一个类里完成所有接口 增删改查(一个)查(所有)
- GenericViewSet就帮助我们完成了这样的继承工作,继承自GenericAPIView与ViewSetMixin,在实现了调用as_view()时传入字典(如{‘get’:‘list’})的映射处理工作的同时,还提供了GenericAPIView提供的基础方法,可以直接搭配Mixin扩展类使用。
# ========================== 5 GenericViewSet =============================================
from rest_framework.viewsets import GenericViewSet
class BookView(GenericViewSet):
def list(self, request):
books = Book.objects.all()
bs = BookSerializer(instance=books, many=True)
return Response(bs.data)
def create(self, request):
bs = BookSerializer(data=request.data)
if bs.is_valid():
bs.save()
return Response(bs.data)
else:
return Response(bs.errors)
def retrieve(self, request, pk):
book = Book.objects.get(pk=pk)
bs = BookSerializer(instance=book)
return Response(bs.data)
def update(self, request, pk):
instance = Book.objects.get(pk=pk)
bs = BookSerializer(instance=instance, data=request.data)
if bs.is_valid():
bs.save()
return Response(bs.data)
else:
return Response(bs.errors)
def delete(self, request, pk):
Book.objects.get(pk=pk).delete()
return Response(status=status.HTTP_204_NO_CONTENT)
# urls.py
from django.urls import path, re_path
from vset.views import BookView
urlpatterns = [
# path("set", views.BookView.as_view({"http请求":"视图方法"})),
path("books/", BookView.as_view({
"get": "list",
"post": "create"
})),
re_path("^books/(?P<pk>\d+)$", BookView.as_view({
"get": "retrieve",
"put": "update",
"delete": "delete",
})),
]
八、GenericViewSet(GenericViewSet 极简版本)(了解)
- 使用最少得代码实现增删改查接口,不适用
# ========================== 6 GenericViewSet 极简版本=============================================
"""
注意:需要匹配相应继承的方法 如ListModelMixin的list方法需要在url中对应get方法 {"get":"list"}
"""
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
"""允许将增删改查写到同一个类中 通过url的as_view()来区分"""
class BookView(GenericViewSet, ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin,
DestroyModelMixin):
queryset = Book.objects
serializer_class = BookSerializers
- 路由
# urls.py
from django.urls import path, re_path
from vset.views import BookView
urlpatterns = [
# path("set", views.BookView.as_view({"http请求":"视图方法"})),
re_path('book/(?P<pk>\d+)', views.BookView.as_view({
"get": "retrieve",
"put": "update",
"delete": "destroy",
})),
path('book/', views.BookView.as_view({
"get": "list",
"post": "create"
})),
]
二、认证与权限
1 认证
视图类为什么需要 authentication_classes
GenericAPIView
=>·APIView
=> APIView(View).as_view()
中super().as_view()
=> base.py的View.view()
调用self.dispatch
(明确self是谁非常关键)=> 执行APIView
的dispatch
(存在重写dispatch)请参考13调用规则 2 self的调用=>执行 APIView
的self.initial
(认证、权限、限流组件三件套)=>self.perform_authentication(request)
(权限也在这里 self.check_permissions(request)
)=>APIView
中的perform_authentication
返回了requests.user
=>rest_framework
的requests.py
的Request
的user
=>Request
的self._authenticate()
=>Request
中_authenticate
中Request
中self.authenticators
来自于init
方法=>寻找在哪里进行初始化的APIView
中dispatch
中的self.initialize_request
=>self.get_authenticators()
=> get_authenticators(self):
=>[auth() for auth in self.authentication_classes]
=>APIView
中存在类属性authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
=>rest_framework\settings.py
中的DEFAULTS 中,当然如果在视图类中重写,self就会去找视图类的authentication_classes
# rest_framework.py class APIView
def initial(self, request, *args, **kwargs):
# Ensure that the incoming request is permitted
self.perform_authentication(request)
self.check_permissions(request)
self.check_throttles(request)
# rest_framework.py class APIView
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
上面这一段代码user_auth_tuple = authenticator.authenticate(self)
导致要实现自定义类必须有authenticate方法
class APIView(View):
def as_view(cls):
view = super().as_view() # # as_view也会访问View.view()
return view
def dispatch(self,request,*args,**kwargs):
# 构建新的request对象
request = self.initialize_request(request, *args, **kwargs)
self.request =request
# 初始化:认证、权限、限流组件三件套
self.initial(request,*args,**kwargs)
# 分发逻辑
handler = getattr(self, request.method.lower())
return handler(request,*args,**kwargs)
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]
DEFAULTS = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication'
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny',
]
}
- 上面调用链存在一个问题django drf中的认证权限字典在DEFAULTS字典lib/python3.6/site-packages/rest_framework/settings.py如何配置到我项目的settings.py中呢?
- 总结:一切以项目中中的
settings.py``REST_FRAMEWORK
为准
“”“drf配置信息必须全部写在REST_FRAMEWORK配置项中”“”
# 项目中的settings.py
REST_FRAMEWORK = {
# 配置认证方式的选项【drf的认证是内部循环遍历每一个注册的认证类,一旦认证通过识别到用户身份,则不会继续循环】
'DEFAULT_AUTHENTICATION_CLASSES': (
'drfdemo.authentication.CustomAuthentication', # 自定义认证
'rest_framework.authentication.SessionAuthentication', # session认证
'rest_framework.authentication.BasicAuthentication', # 基本认证
)
}
Django REST Framework (DRF) 会自动读取你在项目 settings.py
文件中的自定义配置,是因为 DRF 的设计采用了 “可配置默认设置” 的机制。这一机制通过以下几个关键步骤来实现:
-
加载项目中的
settings.py
:
Django 启动时,会加载项目的settings.py
,其中的REST_FRAMEWORK
字典将会定义 DRF 的配置项。 -
DRF 的
Settings
类:
DRF 内部有一个Settings
类(位于rest_framework.settings
模块中),这个类会负责加载和解析配置项。在初始化时,它会尝试从 Django 项目的全局设置中(即settings.py
)读取REST_FRAMEWORK
配置字典。 -
优先使用项目中的配置:
Settings
类会优先使用settings.py
中定义的REST_FRAMEWORK
配置项,而不是DEFAULTS
中的默认设置。具体步骤如下:- DRF 首先检查
settings.py
中是否存在REST_FRAMEWORK
字典。 - 如果有,则使用字典中的配置值覆盖默认的
DEFAULTS
配置。 - 如果某个配置项在
REST_FRAMEWORK
字典中未定义,则回退到DEFAULTS
中的默认值。
- DRF 首先检查
-
动态读取配置:
当 DRF 需要访问某个配置项时(例如,查看DEFAULT_AUTHENTICATION_CLASSES
的值),Settings
类会动态地从settings.py
中的REST_FRAMEWORK
中读取这个配置。这样设计允许开发者根据需要自定义配置项,而无需修改 DRF 的源代码。
这种机制的优点是 DRF 的配置既灵活又易于管理,允许开发者在项目中定制自己需要的认证、权限、限流等行为,适应各种需求。
2 权限
permission_classes 调用链和认证的调用链差不多不赘述了
# 关于REST_FRAMEWORK的所有配置项都是填写在django的settings配置文件中的。
# 所有的REST_FRAMEWORK都要填写在 REST_FRAMEWORK的配置项,而且配置只能大写!!
REST_FRAMEWORK = {
# # 认证全局配置
# 'DEFAULT_AUTHENTICATION_CLASSES':[
# # 默认由drf提供的认证方式
# 'rest_framework.authentication.SessionAuthentication', # session认证
# 'rest_framework.authentication.BasicAuthentication', # 基本认证
# # 将来开发中,我们还可以自己实现属于自己项目的认证方式
# 'drfdemo.authentications.CustomAuthentication',
# ],
# # 权限全局配置
# 'DEFAULT_PERMISSION_CLASSES': [
# # 设置所有视图只能被已经登录认证过的用户访问
# 'rest_framework.permissions.IsAuthenticated',
# ]
}
自定义需要
def has_permission(self, request, view)
- 视图类需要如下
permission_classes = (IsAuthenticated,)
若是登录接口那么不需要认证则在视图类属性中定义一个空的
根据继承关系 类视图的属性是最先被找到的因此可以进行覆盖
permission_classes =None
# 或者
permission_classes=()
跨域配置
安装 django-cors-headers
pip install django-cors-headers
使用和配置
-
在
settings.py
中配置-
添加到已安装的应用中:
INSTALLED_APPS = [ ... 'corsheaders', ]
-
添加到中间件:
确保corsheaders.middleware.CorsMiddleware
放在CommonMiddleware
前。MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', ... ]
-
-
基本跨域设置
-
允许所有域访问(仅限开发环境,不推荐在生产环境使用):
CORS_ALLOW_ALL_ORIGINS = True
-
或仅允许特定域名:
CORS_ALLOWED_ORIGINS = [ "http://example-frontend.com", "http://another-frontend.com", ]
-
-
其他常用配置
- 允许跨域时发送凭据(如 Cookies):
CORS_ALLOW_CREDENTIALS = True
- 允许特定的 HTTP 方法:
CORS_ALLOW_METHODS = [ "GET", "POST", "PUT", "DELETE", "OPTIONS", ]
- 允许特定的请求头:
CORS_ALLOW_HEADERS = [ "content-type", "authorization", "x-csrf-token", ]
- 允许跨域时发送凭据(如 Cookies):
总结
1 视图类主要看 七、GenericViewSet
一般使用此视图进行开发
结合项目进行编写
django开源项目视图类
django开源项目视图类2