Drf框架使用

目录

1、快速上手

1、安装

2、配置,在settings.py中添加配置

3、URL和视图

2、请求数据的封装

3、版本控制(versioning_class)

3、1URL的GET参数传递(*)

3、2URL路径传递(*)

4、认证(authentication_classes)

4、1快速使用

4、2 关于 ”返回None“

4、3必须认证成功之后才能访问

4、4未认证用户也能访问

4、5关于多个认证类

5、权限(permission_classes)

5、1快速使用

5、2关于多个权限类

1、权限组件内部处理机制:按照列表的顺序逐一执行 has_permission 方法,如果返回True,则继续执行后续的权限类;如果返回None或False,则抛出权限异常并停止后续权限类的执行。

2、全局配置

5、3权限补充(has_object_permission)

6、限流

6、1快速使用

 6、1、1配置redis

6、1、2视图展示

6、1、3注意事项(使用限流必须要做的)

6、2多个限流类

6、3全局配置

6、4不要太死板,后期一定要根据自己的需求来看源码的执行流程,重写里面的方法

1、根据请求方式判断是否会限流

2、throttle_success才往列表里面添加数据

3、重写throttle_failure(自定义返回异常)

7、Serializer校验和序列化(*)

 8、视图

8.1 APIView

8.2 GenericAPIView

8.3 GenericViewSet

8.4 五大类

9、条件搜索和分页

10、路由


1、快速上手

1、安装

pip install djangorestframework==3.12.4

2、配置,在settings.py中添加配置

INSTALLED_APPS = [
    ...
    # 注册rest_framework(drf)
    'rest_framework',
]

# drf相关配置以后编写在这里 
REST_FRAMEWORK = {
   
}

3、URL和视图

1、URL

# urls.py

from django.urls import path
from app01 import views

urlpatterns = [
    path('users/', views.UserView.as_view()),
]

2、视图

from rest_framework.views import APIView
from rest_framework.response import Response


class UserView(APIView):
    def get(self, request, *args, **kwargs):
        return Response({"code": 1000, "data": "xxx"})

    def post(self, request, *args, **kwargs):
        return Response({"code": 1000, "data": "xxx"})

drf中重写了 as_viewdispatch方法,其实就是在原来django的功能基础上添加了一些功能,例如:

  • as_view,免除了csrf 验证,一般前后端分离不会使用csrf token认证(后期会使用jwt认证)。

  • dispatch,内部添加了 版本处理、认证、权限、访问频率限制等诸多功能(后期逐一讲解)

2、请求数据的封装

在使用drf框架开发时,视图中的request对象与原来的有些不同,例如:

from rest_framework.views import APIView
from rest_framework.response import Response
from django.views import View
from rest_framework.request import Request


class UserView(APIView):
    def get(self, request, *args, **kwargs):
        
        # 通过对象的嵌套直接找到原request,读取相关值
        request._request.method
        request._request.GET
        request._request.POST
        request._request.body
        
        # 举例:
        	content-type: url-form-encoded
        	v1=123&v2=456&v3=999
            django一旦读取到这个请求头之后,就会按照 {"v1":123,"v2":456,"v3":999}
            
            content-type: application/json
            {"v1":123,"v2":456}
            request._request.POST
            request._request.body
        
        # 直接读取新request对象中的值,一般此处会对原始的数据进行一些处理,方便开发者在视图中使用。
        request.query_params  # 内部本质上就是 request._request.GET
        request.data # 内部读取请求体中的数据,并进行处理,例如:请求者发来JSON格式,他的内部会对json字符串进行反序列化。
        
        # 通过 __getattr__ 去访问 request._request 中的值
        request.method

详细:

# 通过对象的嵌套直接找到原request,读取相关值
request._request.method
request._request.GET
request._request.POST
request._request.body

# 直接读取新request对象中的值,一般此处会对原始的数据进行一些处理,方便开发者在视图中使用。
request.query_params  # 内部本质上就是 request._request.GET
request.data # 内部读取请求体中的数据,并进行处理,例如:请求者发来JSON格式,他的内部会对json字符串进行反序列化。

# 通过 __getattr__ 去访问 request._request 中的值
request.method

3、版本控制(versioning_class)

在restful规范中要去,后端的API中需要体现版本。

drf框架中支持5种版本的设置。

3、1URL的GET参数传递(*)

视图:

from rest_framework.versioning import QueryParameterVersioning

class UserView2(ModelViewSet):

    versioning_class = QueryParameterVersioning

    def post(self,request):
        print(request.version)

全局配置,setting.py

# settings.py

REST_FRAMEWORK = {
    "VERSION_PARAM": "v",    #接受传递版本的参数,v=v2
    "DEFAULT_VERSION": "v1",     #默认版本
    "ALLOWED_VERSIONS": ["v1", "v2", "v3"],    #只有版本允许,才能获取版本,默认版本为允许版本
    "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.QueryParameterVersioning"  
#设置全局配置
}

3、2URL路径传递(*)

视图:

from rest_framework.versioning import URLPathVersioning


class UserView2(ModelViewSet):

    versioning_class = URLPathVersioning

    def post(self,request):
        print(request.version)

全局配置,setting.py

# settings.py

REST_FRAMEWORK = {
    "VERSION_PARAM": "v",    #接受传递版本的参数,v=v2
    "DEFAULT_VERSION": "v1",     #默认版本
    "ALLOWED_VERSIONS": ["v1", "v2", "v3"],    #只有版本允许,才能获取版本,默认版本为允许版本
    "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning"  
#设置全局配置
}

注意:可以通过request.version获取到版本

4、认证(authentication_classes

在开发后端的API时,不同的功能会有不同的限制,例如:

  • 无需认证,就可以访问并获取数据。

  • 需认证,用户需先登录,后续发送请求需携带登录时发放的凭证(后期会讲jwt)

4、1快速使用

视图:

class UserView2(ModelViewSet):
    authentication_classes = ["MyAuth1", "MyAuth2"]

全局配置,settings.py

REST_FRAMEWORK = {
    "UNAUTHENTICATED_USER": lambda: None,   #都没有通过认证时,request.user=的值
    "UNAUTHENTICATED_TOKEN": lambda: None,  #都没有通过认证时,request.auth=的值
    "DEFAULT_AUTHENTICATION_CLASSES":["xxxx.xxxx.xx.类名","xxxx.xxxx.xx.类名",]
}

执行规程:

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed

# 必须认证成功之后才能访问
class TokenAuthentication(BaseAuthentication):
    def authenticate(self, request):
        token = request.query_params.get("token")
        if not token:
            raise AuthenticationFailed({"code": return_code.AUTH_FAILED, "error": "认证失败"})
        user_object = models.UserInfo.objects.filter(token=token).first()
        if not user_object:
            raise AuthenticationFailed({"code": return_code.AUTH_FAILED, "error": "认证失败"})

        if datetime.datetime.now() > user_object.token_expiry_date:
            raise AuthenticationFailed({"code": return_code.AUTH_OVERDUE, "error": "认证过期"})

        return user_object, token

    def authenticate_header(self, request):
        return 'Bearer realm="API"'

在视图类中设置类变量 authentication_classes的值为 认证类 TokenAuthentication,表示此视图在执行内部功能之前需要先经过 认证。

认证类的内部就是去执行:authenticate方法,根据返回值来表示认证结果

  • 抛出异常AuthenticationFailed,表示认证失败。内部还会执行 authenticate_header将返回值设置给响应头 WWW-Authenticate

  • 返回含有两个元素的元组,表示认证成功,并且会将元素的第1个元素赋值给 request.user、第2个值赋值给request.auth

第1个值,一般是用户对象。
第2个值,一般是token
  • 返回None,表示继续调用 后续的认证类 进行认证(上述案例未涉及)

4、2 关于 ”返回None“

在视图类的 authentication_classes 中定义认证类时,传入的是一个列表,支持定义多个认证类。

当出现多个认证类时,drf内部会按照列表的顺序,逐一执行认证类的 authenticate 方法,如果 返回元组 或 抛出异常 则会终止后续认证类的执行;如果返回None,则意味着继续执行后续的认证类。

如果所有的认证类authenticate都返回了None,则默认 request.user="AnonymousUser" 和 request.auth=None,也可以通过修改配置文件来修改默认值。

修改默认值:

REST_FRAMEWORK = {
 "UNAUTHENTICATED_USER": lambda: None,
 "UNAUTHENTICATED_TOKEN": lambda: None,
}

当某个API,已认证 未认证 的用户都可以方法时,比如:

  • 已认证用户,访问API返回该用户的视频播放记录列表。

  • 未认证用户,访问API返回最新的的视频列表。

注意:不同于之前的案例,之前案例是:必须认证成功后才能访问,而此案例则是已认证和未认证均可访问。

4、3必须认证成功之后才能访问

即:认证不通过,直接报异常

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed


# 必须认证成功之后才能访问
class TokenAuthentication(BaseAuthentication):
    def authenticate(self, request):
        token = request.query_params.get("token")
        if not token:
            raise AuthenticationFailed({"code": return_code.AUTH_FAILED, "error": "认证失败"})
        user_object = models.UserInfo.objects.filter(token=token).first()
        if not user_object:
            raise AuthenticationFailed({"code": return_code.AUTH_FAILED, "error": "认证失败"})

        if datetime.datetime.now() > user_object.token_expiry_date:
            raise AuthenticationFailed({"code": return_code.AUTH_OVERDUE, "error": "认证过期"})

        return user_object, token

    def authenticate_header(self, request):
        return 'Bearer realm="API"'

4、4未认证用户也能访问

即:

登录,可以访问 request.user

不登录,也可以访问 request.user=None

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed

# 登录,可以访问  request.user
# 不登录,也可以访问  request.user=None

class UserAnonTokenAuthentication(BaseAuthentication):
    def authenticate(self, request):
        token = request.query_params.get("token")
        if not token:
            return None
        user_object = models.UserInfo.objects.filter(token=token).first()
        if not user_object:
            return None

        if datetime.datetime.now() > user_object.token_expiry_date:
            return None

        return user_object, token

    def authenticate_header(self, request):
        return 'Bearer realm="API"'

4、5关于多个认证类

一般情况下,编写一个认证类足矣。

当项目中可能存在多种认证方式时,就可以写多个认证类。例如,项目认证支持:

  • 在请求中传递token进行验证。

  • 请求携带cookie进行验证。

  • 请求携带jwt进行验证(后期讲)。

  • 请求携带的加密的数据,需用特定算法解密(一般为app开发的接口都是有加密算法)

注意:此示例后续在视图中读取的 request.user 的值为None时,表示未认证成功;不为None时,则表示认证成功。

全局配置

在每个视图类的类变量 authentication_classes 中可以定义,其实在配置文件中也可以进行全局配置,例如:

REST_FRAMEWORK = {
    "UNAUTHENTICATED_USER": lambda: None,
    "UNAUTHENTICATED_TOKEN": lambda: None,
    "DEFAULT_AUTHENTICATION_CLASSES":["xxxx.xxxx.xx.类名","xxxx.xxxx.xx.类名",]
}

5、权限(permission_classes)

认证,根据用户携带的 token/其他 获取当前用户信息。

权限,读取认证中获取的用户信息,判断当前用户是否有权限访问,例如:普通用户、管理员、超级用户,不同用户具有不同的权限。

5、1快速使用

定义:权限类

class PermissionA(BasePermission):
    message = {"code": 1003, 'data': "无权访问"}

    def has_permission(self, request, view):
        if request.user.role == 2:
            return True
        return False
	
    # 暂时先这么写
    def has_object_permission(self, request, view, obj):
        return True

注意:has_permission针对的是某个用户有没有权限

has_object_permission针对的是用户对于某一条数据有没有权限

视图:

class OrderView(APIView):
   permission_classes = [PermissionA,]

    def get(self, request, *args, **kwargs):
        print(request.user)
        return Response({"code": 0, "data": {"user": None, 'list': [1, 2, 3]}})

5、2关于多个权限类

当开发过程中需要用户同时具备多个权限(缺一不可)时,可以用多个权限类来实现。

1、权限组件内部处理机制:按照列表的顺序逐一执行 has_permission 方法,如果返回True,则继续执行后续的权限类;如果返回None或False,则抛出权限异常并停止后续权限类的执行。

调用GenericAPIView中的self.get_object 方法时,会按照 permission_classes中权限组件的顺序,依次执行他们的 has_object_permission 方法。

self.get_object其实就根据用户传入的 pk,搜索并获取某个对象的过程。

2、全局配置

REST_FRAMEWORK = {
    "DEFAULT_PERMISSION_CLASSES":["xxxx.xxxx.xx.类名","xxxx.xxxx.xx.类名",]
}

5、3权限补充(has_object_permission

在之前定义权限类时,类中可以定义两个方法:has_permissionhas_object_permission

  • has_permission ,在请求进入视图之前就会执行。

  • has_object_permission,当视图中调用 self.get_object时就会被调用(删除、更新、查看某个对象时都会调用),一般用于检查对某个对象是否具有权限进行操作

class PermissionA(BasePermission):
    message = {"code": 1003, 'data': "无权访问"}
​
    def has_permission(self, request, view):
        exists = request.user.roles.filter(title="员工").exists()
        if exists:
            return True
        return False
​
    def has_object_permission(self, request, view, obj):
        return True

所以,让我们在编写视图类时,如果是直接获取间接继承了 GenericAPIView,同时内部调用 get_object方法,这样在权限中通过 has_object_permission 就可以进行权限的处理。

6、限流

限流,限制用户访问频率,例如:用户1分钟最多访问100次 或者 短信验证码一天每天可以发送50次, 防止盗刷。

  • 对于匿名用户,使用用户IP作为唯一标识。

  • 对于登录用户,使用用户ID或名称作为唯一标识。

6、1快速使用

 6、1、1配置redis

pip3 install django-redis
# settings.py
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "PASSWORD": "qwe123",
        }
    }
}

6、1、2视图展示

# views.py

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import exceptions
from rest_framework import status
from rest_framework.throttling import SimpleRateThrottle
from django.core.cache import cache as default_cache


class ThrottledException(exceptions.APIException):
    status_code = status.HTTP_429_TOO_MANY_REQUESTS
    default_code = 'throttled'

#自定义限流类
class MyRateThrottle(SimpleRateThrottle):
    cache = default_cache  # 访问记录存放在django的缓存中(需设置缓存)
    scope = "user"  # 构造缓存中的key
    cache_format = 'throttle_%(scope)s_%(ident)s'

    # 设置访问频率,例如:1分钟允许访问10次
    # 其他:'s', 'sec', 'm', 'min', 'h', 'hour', 'd', 'day'
    THROTTLE_RATES = {"user": "10/m"}

    def get_cache_key(self, request, view):
        if request.user:
            ident = request.user.pk  # 用户ID
        else:
            ident = self.get_ident(request)  # 获取请求用户IP(去request中找请求头)

        # throttle_u # throttle_user_11.11.11.11ser_2

        return self.cache_format % {'scope': self.scope, 'ident': ident}

    def throttle_failure(self):
        wait = self.wait()
        detail = {
            "code": 1005,
            "data": "访问频率限制",
            'detail': "需等待{}s才能访问".format(int(wait))
        }
        raise ThrottledException(detail)


#视图
class OrderView(APIView):
    throttle_classes = [MyRateThrottle, ]

    def get(self, request):
        return Response({"code": 0, "data": "数据..."})

6、1、3注意事项(使用限流必须要做的)

一定要重写get_cache_key方法,它返回的是存储在redis的key

    def get_cache_key(self, request, view):
        if request.user:
            ident = request.user.pk  # 用户ID
        else:
            ident = self.get_ident(request)  # 获取请求用户IP(去request中找请求头)

        # throttle_u # throttle_user_11.11.11.11ser_2

        return self.cache_format % {'scope': self.scope, 'ident': ident}

6、2多个限流类

本质,每个限流的类中都有一个 allow_request 方法,此方法内部可以有三种情况:

  • 返回True,表示当前限流类允许访问,继续执行后续的限流类。

  • 返回False,表示当前限流类不允许访问,继续执行后续的限流类。所有的限流类执行完毕后,读取所有不允许的限流,并计算还需等待的时间。

  • 抛出异常,表示当前限流类不允许访问,后续限流类不再执行。

6、3全局配置

REST_FRAMEWORK = {
    "DEFAULT_THROTTLE_CLASSES":["xxx.xxx.xx.限流类", ],
    "DEFAULT_THROTTLE_RATES": {
        "user": "10/m",
        "xx":"100/h"
    }
}

6、4不要太死板,后期一定要根据自己的需求来看源码的执行流程,重写里面的方法

1、根据请求方式判断是否会限流

class NewsView(DigListModelMixin, DigCreateModelMixin, GenericViewSet):
  # 自定义的类变量
    throttle_objects = [NewsCreateRateThrottle(), ]   


    def get_throttles(self):
        if self.request.method == "POST":
            return self.throttle_objects
        return []

根据请求方式不同决定是否要调用限流类:一般get请求不会限制访问次数,post会限制次数

2、throttle_success才往列表里面添加数据

视图:

class NewsView(DigListModelMixin, DigCreateModelMixin, GenericViewSet):
    filter_backends = [SelfFilterBackend, DjangoFilterBackend]
    filterset_class = NewsFilterSet

    # 未删除 & 属于当前用户创建的新闻资讯
    queryset = models.News.objects.filter(deleted=False).order_by('-id')
    serializer_class = NewsSerializer

    # 自定义的类变量
    throttle_objects = [NewsCreateRateThrottle(), ]

    def perform_create(self, serializer):
        # 1.创建新闻资讯
        # 2.自己对自己的内容做推荐
        #       - 推荐数量+1
        #       - 推荐记录  用户&资讯
        serializer.save(user=self.request.user)

        # 数据库中已增加成功,调用限流的那个done方法
        for throttle in self.get_throttles():
            throttle.done()

    def get_throttles(self):
        if self.request.method == "POST":
            return self.throttle_objects
        return []

限流类:throttle_success改为done ,等数据添加完,执行done,可以实现数据添加成功时(将诶口访问成功),将数据加入到redis的限流时间戳

    def throttle_success(self):
        """
        Inserts the current request's timestamp along with the key
        into the cache.
        """
        #self.history.insert(0, self.now)
        #self.cache.set(self.key, self.history, self.duration)
        return True


        def done(self):
        """
        Inserts the current request's timestamp along with the key
        into the cache.
        """
        self.history.insert(0, self.now)
        self.cache.set(self.key, self.history, self.duration)
        return True

在请求完成时,数据添加成功,在调用done方法,把该次请求的时间添加到redis的缓存中

3、重写throttle_failure(自定义返回异常)

不满足限流条件直接触发异常:

# views.py
from rest_framework import exceptions
from rest_framework import status

class ThrottledException(exceptions.APIException):
    status_code = status.HTTP_429_TOO_MANY_REQUESTS
    default_code = 'throttled'

#自定义限流类
class MyRateThrottle(SimpleRateThrottle):
    cache = default_cache  # 访问记录存放在django的缓存中(需设置缓存)
    scope = "user"  # 构造缓存中的key
    cache_format = 'throttle_%(scope)s_%(ident)s'

    def throttle_failure(self):
        wait = self.wait()
        detail = {
            "code": 1005,
            "data": "访问频率限制",
            'detail': "需等待{}s才能访问".format(int(wait))
        }
        raise ThrottledException(detail)

注意:需要自定义异常的类,默认的exception.threttld只会接受一个wait()数字

7、Serializer校验和序列化(*)

连接如下:

https://blog.csdn.net/m0_73399600/article/details/134804798?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22134804798%22%2C%22source%22%3A%22m0_73399600%22%7Dicon-default.png?t=N7T8https://blog.csdn.net/m0_73399600/article/details/134804798?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22134804798%22%2C%22source%22%3A%22m0_73399600%22%7D

 8、视图

8.1 APIView

  • View,django

  • APIView,drf,在请求到来时,新增了:免除csrf、请求封装、版本、认证、权限、限流的功能

APIView是drf中 “顶层” 的视图类,在他的内部主要实现drf基础的组件的使用,例如:版本、认证、权限、限流等。

8.2 GenericAPIView

GenericAPIView 继承APIView,在APIView的基础上又增加了一些功能。例如:get_querysetget_object、get_serializer、filter_backends、pagination_class等。

直接体现为:组合搜索、分页

实际在开发中一般不会直接继承它,他更多的是担任 中间人的角色,为子类提供公共功能。

注意:最大的意义,将数据库查询、序列化类提取到类变量中,后期再提供公共的get/post/put/delete等方法,让开发者只定义类变量,自动实现增删改查。

8.3 GenericViewSet

GenericViewSet类中没有定义任何代码,他就是继承 ViewSetMixinGenericAPIView,也就说他的功能就是将继承的两个类的功能继承到一起。

  • GenericAPIView,将数据库查询、序列化类的定义提取到类变量中,便于后期处理。

  • ViewSetMixin,将 get/post/put/delete 等方法映射到 list、create、retrieve、update、partial_update、destroy方法中,让视图不再需要两个类。

注意:开发中一般也很少直接去继承他,因为他也属于是 中间人类,在原来 GenericAPIView 基础上又增加了一个映射而已。

8.4 五大类

在drf的为我们提供好了5个用于做 增、删、改(含局部修改)、查列表、查单个数据的5个类(需结合 GenericViewSet 使用)。

# urls.py

from django.urls import path, re_path, include
from app01 import views

urlpatterns = [
    path('api/users/', views.UserView.as_view({"get":"list","post":"create"})),
    path('api/users/<int:pk>/', views.UserView.as_view({"get":"retrieve","put":"update","patch":"partial_update","delete":"destroy"})),
]
# views.py

from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import (
    ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin,
    DestroyModelMixin, ListModelMixin
)

class UserView(CreateModelMixin,RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin,ListModelMixin,GenericViewSet):
    
	# 认证、权限、限流等
    queryset = models.UserInfo.objects.filter(status=True)
    serializer_class = 序列化类

在这个5个类中已帮我们写好了 listcreateretrieveupdatepartial_updatedestory 方法,我们只需要在根据写 类变量:queryset、serializer_class即可。

在开发过程中使用 五大类ModelViewSet 是比较常见的,并且如果他们内部的某些功能不够用,还可以进行重新某些方法进行扩展。

如果一个视图具备所有的功能

from rest_framework.viewsets import ModelViewSet

问题:drf中提供了这么多视图,以后那个用的比较多?

  • 接口与数据库操作无关,直接继承APIView

  • 接口背后需要对数据库进行操作,一般:ModelViewSetCreateModelMixin、ListModelMixin...

    - 利用钩子自定义功能。
    - 重写某个写方法,实现更加完善的功能。
  • 根据自己公司的习惯,自定义 :ModelViewSetCreateModelMixin、ListModelMixin...

9、条件搜索和分页

连接:

https://blog.csdn.net/m0_73399600/article/details/134808152?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22134808152%22%2C%22source%22%3A%22m0_73399600%22%7Dicon-default.png?t=N7T8https://blog.csdn.net/m0_73399600/article/details/134808152?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22134808152%22%2C%22source%22%3A%22m0_73399600%22%7D

10、路由

针对具备所有功能的视图:引入router

from rest_framework import routers
from app01 import views

router = routers.SimpleRouter()
router.register(r'api/users', views.UserView)

urlpatterns = [
    # 其他URL
    # path('xxxx/', xxxx.as_view()),
]

urlpatterns += router.urls

也可以利用include,给URL加前缀:

from django.urls import path, include
from rest_framework import routers
from app01 import views

router = routers.SimpleRouter()
router.register(r'users', views.UserView)

urlpatterns = [
    path('api/', include((router.urls, 'app_name'), namespace='instance_name')),
    # 其他URL
    # path('forgot-password/', ForgotPasswordFormView.as_view()),
]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值