首页IT科技django框架结构(django框架之drf(部分讲解))

django框架结构(django框架之drf(部分讲解))

时间2025-06-15 16:06:00分类IT科技浏览3651
导读:一、认证组件 简介:...

一            、认证组件

简介:

登录认证的限制

认证组件是drf框架给我们提供的认证接口             ,它能够在请求进入视图函数/类前进验证(例如:认证用户是否登录)                    ,对不符合认证的请求进行拦截并返回校验失败的信息

(1)                   、登录接口

# 认证是基于登录的接口上面操作的 所以前戏编写一个简单的登录接口 models.py class User(models.Model): # 简易的用户信息账号密码 username = models.CharField(max_length=32) password = models.CharField(max_length=32) def __str__(self): return self.username 跟User表是一对一外键关联      ,存储用户登录状态用的 [这个表可以没有         ,如果没有                    ,把字段直接写在User表上也可以] class UserToken(models.Model): # 用户信息登录记录表 user = models.OneToOneField(to=User, on_delete=models.CASCADE) # 一对一关联 token = models.CharField(max_length=32, null=True) # 如果用户没有登录则没有值 如果登录则有值 views.py 登录接口功能:自动生成路由+登录功能         ,不用序列化      ,因此继承ViewSet即可 class UserView(ViewSet): @action(methods=[POST], detail=False, url_path=login, url_name=login) def login(self, request): username = request.data.get(username) # 获取用户名与密码 password = request.data.get(password) user = User.objects.filter(username=username, password=password).first() # 比对用户名与密码 if user: token = str(uuid.uuid4()) # uuid4 随机获得永不重复的字符串 机制跟Cookie中的验证码一样 # 在userToken表中存储一下:1 从来没有登录过                    ,插入一条            , 2 登录过   ,修改记录 UserToken.objects.update_or_create(defaults={token: token}, user=user) # 通过user去UserToken表中查数据                    ,如果能查到               ,使用defaults的数据更新,如果查不到                 ,直接通过user和defaults的数据新增 # kwargs 传入的东西查找                   ,能找到   ,使用defaults的更新             ,否则新增一条 return Response({code: 100, msg: 登录成功, token: token}) else: return Response({code: 101, msg: 用户名或密码错误}) urls.py from rest_framework.routers import SimpleRouter, DefaultRouter router = SimpleRouter() router.register(users, views.UserView, users) urlpatterns += router.urls 这个时候一个简单的登录接口就写好了 每次登录都会更新Token 相当于登录了之前的设备就无效了

update_or_create源码如下:

def update_or_create(self, defaults=None, **kwargs): defaults = defaults or {} self._for_write = True with transaction.atomic(using=self.db): try: obj = self.select_for_update().get(**kwargs) except self.model.DoesNotExist: params = self._extract_model_params(defaults, **kwargs) obj, created = self._create_object_from_params(kwargs, params, lock=True) if created: return obj, created for k, v in defaults.items(): setattr(obj, k, v() if callable(v) else v) obj.save(using=self.db) return obj, False

(2)        、认证组件使用步骤

1.需要写一个认证类                    ,因此我们需要在应用中另外创建一个py文件编写认证类      ,需要继承BaseAuthentication这个类

通过查看源码我们可以发现有个authenticate方法需要我们重写         ,否则就会报错                    ,这就是我们需要编写认证功能的类 class BaseAuthentication: def authenticate(self, request): raise NotImplementedError(".authenticate() must be overridden.") def authenticate_header(self, request): pass

2.重写authenticate方法         ,在该方法在中实现登录认证

token在哪带的?如何认证它是登录了的?

用token来判断是否登陆      ,登陆了在访问的时候带上token                    ,目前阶段我们直接在地址栏中携带token的数据            ,后面可以在请求头中添加token的数据

3         、如果认证成功   ,返回两个值【返回None或两个值(固定的:当前登录用户                    ,token)】

4                  、认证不通过               ,用AuthenticationFailed类抛异常

代码如下:

authenticate.py(认证类) # 自己写的认证类,继承某个类 from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailed from .models import UserToken class LoginAuth(BaseAuthentication): def authenticate(self, request): # 在这里实现认证                 ,如果是登录的                   ,继续往后走返回两个值   ,如果不是抛异常 # 请求中是否携带token             ,判断是否登录                    ,放在地址栏中 token = request.query_params.get(token, None) # 查找是否有token这个变量名的值      ,如果没有就返回None         ,默认好像返回的是数字 if token: # 前端传入token了                    ,去表中查         ,如果能查到      ,登录了                    ,返回两个值[固定的:当前登录用户            ,token] user_token = UserToken.objects.filter(token=token).first() if user_token: return user_token.user, token else: # 没有登录抛异常 raise AuthenticationFailed(token认证失败) else: raise AuthenticationFailed(token没传) # 前端传入的请求头中的数据从哪取? GET   ,body                    ,POST               ,data

5           、认证类的使用

当我们编写好了认证类中的认证代码,接着就需要导入到视图层然后使用他 from rest_framework.generics import ListAPIView, RetrieveAPIView from rest_framework.viewsets import ViewSetMixin from .authenticate import LoginAuth # 查询所有 class BookView(ViewSetMixin, ListAPIView): queryset = Book.objects.all() serializer_class = BookSerializer class BookDetailView(ViewSetMixin, RetrieveAPIView): queryset = Book.objects.all() serializer_class = BookSerializer authentication_classes = [LoginAuth] # 需要写一个认证类                 ,需要咱们自行编写

6      、局部使用和全局使用

局部使用:只在某个视图类中使用【当前视图类管理的所有接口】 class BookDetailView(ViewSetMixin, RetrieveAPIView): authentication_classes = [LoginAuth] 全局使用:在配置文件settings.py中编写                   ,全局所有接口都生效 REST_FRAMEWORK = { DEFAULT_AUTHENTICATION_CLASSES:[app01.authenticate.LoginAuth] }

注意事项:不要在配置文件中乱导入不使用的东西   ,否则会报错             ,但是在导入类似认证类这样的文件时                    ,可以写上导入的代码然后再修改      ,最后写进配置中         ,这样可以减少错误

局部禁用:(登陆接口很明显是不需要校验是否登陆的                    ,因此有了这个局部禁用的需求         ,我们把他的authentication_classes配置成空就是局部禁用) class BookDetailView(ViewSetMixin, RetrieveAPIView): authentication_classes = []

7                  、测试路由参考

(3)              、整体代码

views.py

# 查询所有 class BookView(ViewSetMixin, ListAPIView): queryset = Book.objects.all() serializer_class = BookSerializer # 查询单个 class BookDetailView(ViewSetMixin, RetrieveAPIView): queryset = Book.objects.all() serializer_class = BookSerializer authentication_classes = [LoginAuth] # 需要写一个认证类      ,需要咱们自行编写

authenticate.py(认证类)

# 自己写的认证类                    ,继承某个类 from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailed from .models import UserToken class LoginAuth(BaseAuthentication): def authenticate(self, request): # 在这里实现认证            ,如果是登录的   ,继续往后走返回两个值                    ,如果不是抛异常 # 请求中是否携带token               ,判断是否登录,放在地址栏中 token = request.query_params.get(token, None) # 查找是否有token这个变量名的值                 ,如果没有就返回None                   ,默认好像返回的是数字 if token: # 前端传入token了   ,去表中查             ,如果能查到                    ,登录了      ,返回两个值[固定的:当前登录用户         ,token] user_token = UserToken.objects.filter(token=token).first() if user_token: return user_token.user, token else: # 没有登录抛异常 raise AuthenticationFailed(token认证失败) else: raise AuthenticationFailed(token没传) # 前端传入的请求头中的数据从哪取? GET                    ,body         ,POST      ,data

urls.py

from django.contrib import admin from django.urls import path, include from app01 import views from rest_framework.routers import SimpleRouter router = SimpleRouter() # 后面这个少的用的多, router.register(user, views.UserView, user) router.register(books, views.BookView, books) router.register(books, views.BookDetailView, books) urlpatterns = [ path(admin/, admin.site.urls), path(api/v1/, include(router.urls)), ]

权限组件

简介:

在我们使用的一些app或者网页中(爱奇艺                    ,腾讯视频)            ,都会有一些会员接口(需要购买会员才能够使用或者观看)   ,权限组件就是对用户的这一权限进行验证                    ,在请求进入视图类/函数代码前进行校验               ,校验失败后直接将请求拦截,并返回校验失败的信息

(1)   、权限组件的使用步骤

模块地址:

from rest_framework.permissions import BasePermission

用法简介:

# 1                  、创建一个专门用于编写权限组件的py文件                 ,写一个权限类                   ,继承BasePermission # 2                 、重写has_permission方法(在该方法在中实现权限认证   ,在这方法中             ,request.user就是当前登录用户) # 3、如果有权限                    ,返回True # 4               、没有权限      ,返回False(定制返回的中文: self.message=中文) # 5                    、局部使用和全局使用 -局部使用: # 在某个视图类中设置接口(不会影响别的视图类) class BookDetailView(ViewSetMixin, RetrieveAPIView): permission_classes = [CommonPermission] -全局使用: # django的settings.py中配置         ,影响全局 REST_FRAMEWORK = { DEFAULT_PERMISSION_CLASSES: [ app01.permissions.CommonPermission, ], } -局部禁用:# 全局配置局部禁用 class BookDetailView(ViewSetMixin, RetrieveAPIView): permission_classes = []

(2)    、代码用法

models.py(修改User表的配置后需要重新进行数据库迁移)

class User(models.Model): username = models.CharField(max_length=32) password = models.CharField(max_length=32) user_type = models.IntegerField(choices=((1, 超级管理员), (2, 普通用户), (3, 2B用户)), default=2)

perssion.py(权限类代码)

# 写权限类                    ,写一个类         ,继承基类BasePermission      ,重写has_permission方法                    ,在方法中实现权限认证,如果有权限return True             ,如果没有权限   ,返回False from rest_framework.permissions import BasePermission class CommonPermission(BasePermission): def has_permission(self, request, view): # 实现权限的控制 ---》知道当前登录用户是谁?当前登录用户是 request.user if request.user.user_type == 1: return True else: # 没有权限                    ,向对象中放一个属性 message # 如果表模型中               ,使用了choice,就可以通过 get_字段名_display() 拿到choice对应的中文 self.message = 您是【%s】                 ,您没有权限 % request.user.get_user_type_display() return False

views.py(视图类代码)

class BookView(ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer # 局部认证 authentication_classes = [LoginAuth] # 权限认证(将编写的频率类导入过来) permission_classes = [CommentPermission]

三            、频率组件

简介:

频率是指                   ,控制某个接口访问频率(次数)

(1)                   、频率组件的使用步骤

模块地址:

from rest_framework.throttling import BaseThrottle, SimpleRateThrottle # BaseThrottle:需要手动编写的代码较多 # SimpleRateThrottle: 需要手动编写的代码较少(用这个)

用法简介

# 1        、创建一个专门用来编写频率组件的py文件   ,写一个频率类             ,继承SimpleRateThrottle # 2         、重写get_cache_key方法                    ,返回什么      ,就以什么做限制----》ip(用户id做限制) # 3                  、配置一个类属性scope = book_5_m # 4           、在django的配置文件中编写频率次数 REST_FRAMEWORK = { DEFAULT_THROTTLE_RATES: { book_5_m: 5/m, # 一分钟五次 }, } # 5      、局部使用和全局使用 -局部使用: # 只影响当前的视图类 class BookView(ModelViewSet): throttle_classes = [CommentThrottle] -全局配置:影响全局 REST_FRAMEWORK = { DEFAULT_THROTTLE_CLASSES: [app01.throttling.CommonThrottle], } -局部禁用: class BookView(ModelViewSet): throttle_classes = [CommentThrottle]

(2)                  、代码用法

throttle.py(频率类代码)

from rest_framework.throttling import BaseThrottle, SimpleRateThrottle class CommentThrottle(SimpleRateThrottle): # 创建一个用于控制频率的变量名(需要传入配置文件) scope = book_5_m def get_cache_key(self, request, view): # 返回什么就以什么做限制(request.META.get(REMOTE_ADDR)以IP做限制) return request.META.get(REMOTE_ADDR)

视图类代码

class BookView(ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer # 频率组件 throttle_classes = [CommentThrottle]

django配置文件

REST_FRAMEWORK = { # 控制访问频率 DEFAULT_THROTTLE_RATES: { book_5_m: 5/m, # 一分钟五次 }, }

四              、过滤的多种用法

简介:

过滤是指在使用查询的时候         ,我们可以通过条件来过滤掉不需要的内容 # restful规范中                    ,要求了         ,请求地址中带过滤条件 -5个接口中      ,只有一个接口需要有过滤和排序                    ,查询所有接口

(1)   、继承APIView自己写

class BookView(APIView): def get(self,request): # 获取get请求携带的参数 name=request.query_params.get(name) # 通过filter进行过滤 books = Book.objects.filter(name=name)

(2)                  、使用drf的内置过滤(继承GenericAPIview)

模块地址: 该方法为模糊查询

from rest_framework.filters import SearchFilter

代码用法:

class BookView(ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer # 实例化过滤对象 filter_backends = [SearchFilter] # 指定过滤的字段(模糊查询) search_fields = [name, price]

搜索方式:

# name或price中只要有关键字就会搜出来 (只能用search=xxx的方式) http://127.0.0.1:8000/api/v1/books/?search=西游记

(3)                 、使用第三方插件过滤(精准过滤)

第三方插件:

# 插件名称: django-filter # 安装插件: pip3.8 install django-filter

模块地址:

from django_filters.rest_framework import DjangoFilterBackend

代码用法:

from rest_framework.viewsets import ModelViewSet from .models import Book from .serializer import BookSerializer from django_filters.rest_framework import DjangoFilterBackend class BookView(ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer # 第三方过滤插件 filter_backends = [DjangoFilterBackend] # 查询的字段 filterset_fields = [pk,name, price]

搜索方式:

http://127.0.0.1:8000/api/books/?price=99 http://127.0.0.1:8000/api/books/?price=99&name=呐喊

4、使用过滤组件

1.定制过滤组件的使用方式与步骤

模块地址:

from rest_framework.filters import BaseFilterBackend

用法简介:

# 1               、创建一个专门用于过滤的py文件            ,写一个类继承BaseFilterBackend # 2                    、重写filter_queryset方法   ,在方法内部进行过滤 # 3    、直接返回过滤后的对象 # 4            、如果没有过滤直接返回所有数据 # 5                   、局部使用 -局部使用: class BookView(ViewSetMixin, ListAPIView): queryset = Book.objects.all() serializer_class = BookSerializer # 在类表内填写过滤的类 filter_backends = [CommonFilter] # 可以定制多个                    ,从左往右               ,依次执行

2.代码用法

过滤类代码filters.py

from rest_framework.filters import BaseFilterBackend class CommonFilter(BaseFilterBackend): # 重写的类,编写过滤吧的内容 def filter_queryset(self, request, queryset, view): # 获取过滤的条件 filter_comment = request.query_params.get(price_gt, None) # 判断前端是否传入过滤条件 if filter_comment: # 根据条件进行赛选内容 books_queryset_filter = queryset.filter(price__gt=100) # 返回过滤后的数据 return books_queryset_filter return queryset

视图类代码

class BookView(ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer # 第三方过滤插件 filter_backends = [CommonFilter]

五        、排序的使用

用法简介

排序需要和自定义过滤继承同一个父类,需要将排序的对象填入在过滤的列表内                 ,并且放在其他参数的前方

模块地址: from rest_framework.filters import OrderingFilter

(2)         、代码用法

视图类代码

from rest_framework.viewsets import ModelViewSet from .models import Book from .serializer import BookSerializer from django_filters.rest_framework import DjangoFilterBackend from .filters import CommonFilter from rest_framework.filters import OrderingFilter class BookView(ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer # 第三方过滤插件(OrderingFilter放在其他过滤参数前) filter_backends = [OrderingFilter, DjangoFilterBackend, CommonFilter] # 查询的字段 filterset_fields = [id, name, price] # 指定排序的字段(-是降序                   ,默认升序) ordering_fields = [price]

搜索用法

# 默认升序 http://127.0.0.1:8000/api/books/?price_gt=60&ordering=price # 降序 http://127.0.0.1:8000/api/books/?price_gt=60&ordering=-price

六                  、分页

分页功能   ,只有查询所有接口             ,才有分页 drf内置了三个分页器                    ,对应三种分页方式 内置的分页类不能直接使用      ,需要继承         ,定制一些参数后才能使用

使用步骤

步骤一:创建一个py文件编写分页用到的自定义类                    ,分页的三个类并不能直接使用         ,需要我们进行配置 步骤二:编写这个自定义类 步骤三:导入视图类中      ,并添加配置

代码 page.py(自定义的分页类)

from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination # 网页用它 class CommonPageNumberPagination(PageNumberPagination): page_size = 2 # 每页显示2条 page_query_param = page # page=10 查询第10页的数据                    ,每页显示2条 page_size_query_param = size # page=10&size=5 查询第10页            ,每页显示5条 max_page_size = 5 # 每页最大显示10条 page_size 每页数目 page_query_param 前端发送的页数关键字名   ,默认为            ”page                   ” page_size_query_param 前端发送的每页数目关键字名                    ,默认为None max_page_size 前端最多能设置的每页数量 # LimitOffset class CommonLimitOffsetPagination(LimitOffsetPagination): default_limit = 3 # 每页显示2条 limit_query_param = limit # limit=3 取3条 offset_query_param = offset # offset=1 从第一个位置开始               ,取limit条 max_limit = 5 # offset=3&limit=2 0 1 2 3 4 5 default_limit 默认限制,默认值与PAGE_SIZE设置一直 limit_query_param limit参数名                 ,默认’limit’ offset_query_param offset参数名                   ,默认’offset’ max_limit 最大limit限制   ,默认None # app 用下面 class CommonCursorPagination(CursorPagination): cursor_query_param = cursor # 查询参数 page_size = 2 # 每页多少条 ordering = id # 排序字段 cursor_query_param:默认查询字段             ,不需要修改 page_size:每页数目 ordering:按什么排序                    ,需要指定

views.py

# 分页功能 必须是继承GenericAPIView       ,如果是继承APIView         ,要自己写(你写) from .page import CommonPageNumberPagination as PageNumberPagination from .page import CommonLimitOffsetPagination as LimitOffsetPagination from .page import CommonCursorPagination as CommonCursorPagination class BookView(ViewSetMixin, ListAPIView): queryset = Book.objects.all() serializer_class = BookSerializer permission_classes = [] authentication_classes = [] throttle_classes = [] # 之前的东西一样用 ,内置的分页类不能直接使用                    ,需要继承         ,定制一些参数后才能使用 # pagination_class = PageNumberPagination #基本分页方式(基本是这种      ,网页端):http://127.0.0.1:8000/api/v1/books/?page=2&size=3 # pagination_class = LimitOffsetPagination # 偏移分页 http://127.0.0.1:8000/api/v1/books/?limit=4&offset=1 # 从第一条开始                    ,取4条 pagination_class = CommonCursorPagination # 游标分页            ,只能下一页   ,上一页                    ,不能跳到中间               ,但它的效率最高,大数据量分页                 ,使用这种较好
声明:本站所有文章                   ,如无特殊说明或标注   ,均为本站原创发布            。任何个人或组织             ,在未征得本站同意时                    ,禁止复制           、盗用      、采集                  、发布本站内容到任何网站              、书籍等各类媒体平台                   。如若本站内容侵犯了原著者的合法权益      ,可联系我们进行处理        。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
看哪个新闻能赚现金(看什么新闻可以有钱赚-司马南呼吁的共同富裕的事情,柳传志帮着付诸实施了?) windows11 恢复(如何在Win11中备份文件并降级回Win10?)