DRF笔记

参考资料

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一般用于getput请求,从数据库给前端数据涉及操作;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是谁非常关键)=> 执行APIViewdispatch(存在重写dispatch)请参考13调用规则 2 self的调用=>执行 APIViewself.initial (认证、权限、限流组件三件套)=>return get()

  • BookView的实例化
    View类中as_view下的view 代码self = cls(**initkwargs) # BookView()指出了我们调用的时候是views.BookView.as_view() 其实BookView就是clscls()相当于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是谁非常关键)=> 执行APIViewdispatch(存在重写dispatch)请参考13调用规则 2 self的调用=>执行 APIViewself.initial (认证、权限、限流组件三件套)=>self.perform_authentication(request)(权限也在这里 self.check_permissions(request))=>APIView中的perform_authentication返回了requests.user=>rest_frameworkrequests.pyRequestuser=>Requestself._authenticate()=>Request_authenticateRequestself.authenticators来自于init方法=>寻找在哪里进行初始化的APIViewdispatch中的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 的设计采用了 “可配置默认设置” 的机制。这一机制通过以下几个关键步骤来实现:

  1. 加载项目中的 settings.py
    Django 启动时,会加载项目的 settings.py,其中的 REST_FRAMEWORK 字典将会定义 DRF 的配置项。

  2. DRF 的 Settings
    DRF 内部有一个 Settings 类(位于 rest_framework.settings 模块中),这个类会负责加载和解析配置项。在初始化时,它会尝试从 Django 项目的全局设置中(即 settings.py)读取 REST_FRAMEWORK 配置字典。

  3. 优先使用项目中的配置
    Settings 类会优先使用 settings.py 中定义的 REST_FRAMEWORK 配置项,而不是 DEFAULTS 中的默认设置。具体步骤如下:

    • DRF 首先检查 settings.py 中是否存在 REST_FRAMEWORK 字典。
    • 如果有,则使用字典中的配置值覆盖默认的 DEFAULTS 配置。
    • 如果某个配置项在 REST_FRAMEWORK 字典中未定义,则回退到 DEFAULTS 中的默认值。
  4. 动态读取配置
    当 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

使用和配置

  1. settings.py 中配置

    • 添加到已安装的应用中:

      INSTALLED_APPS = [
          ...
          'corsheaders',
      ]
      
    • 添加到中间件:
      确保 corsheaders.middleware.CorsMiddleware 放在 CommonMiddleware 前。

      MIDDLEWARE = [
          'corsheaders.middleware.CorsMiddleware',
          'django.middleware.common.CommonMiddleware',
          ...
      ]
      
  2. 基本跨域设置

    • 允许所有域访问(仅限开发环境,不推荐在生产环境使用):

      CORS_ALLOW_ALL_ORIGINS = True
      
    • 或仅允许特定域名:

      CORS_ALLOWED_ORIGINS = [
          "http://example-frontend.com",
          "http://another-frontend.com",
      ]
      
  3. 其他常用配置

    • 允许跨域时发送凭据(如 Cookies)
      CORS_ALLOW_CREDENTIALS = True
      
    • 允许特定的 HTTP 方法
      CORS_ALLOW_METHODS = [
          "GET",
          "POST",
          "PUT",
          "DELETE",
          "OPTIONS",
      ]
      
    • 允许特定的请求头
      CORS_ALLOW_HEADERS = [
          "content-type",
          "authorization",
          "x-csrf-token",
      ]
      

总结

1 视图类主要看 七、GenericViewSet 一般使用此视图进行开发

结合项目进行编写
django开源项目视图类
django开源项目视图类2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值