才有的---》执行流程---》dispatch中----》三大认证
APIView的dispatch
def initial(self, request, *args, **kwargs):
self.perform_authentication(request)
self.check_permissions(request)
self.check_throttles(request)
self.check_permissions(request)
def check_permissions(self, request):
# permission_classes = [AdminPermission]
# self.get_permissions()我们配置再视图类上permission_classes列表中的认证类,一个个的对象
# self.get_permissions() 是 [AdminPermission(),]
for permission in self.get_permissions():
# 写的权限类,要重写has_permission方法
# 猜permission是我们写的权限类的对象
# self 是视图类的对象(BookView,PublisViwe)
if not permission.has_permission(request, self): # 权限没通过
self.permission_denied(
request,
# self.message 错误文字
message=getattr(permission, 'message', None),
code=getattr(permission, 'code', None)
)
def get_permissions(self):
return [permission() for permission in self.permission_classes]
# 翻译:
l=[]
for permission in self.permission_classes:
l.append(permission())
return l
记住:
- 写的权限类,一定要写一个方法has_permission,返回True或False
- 配置再视图类上
4.补充
视图类的方法,必须返回 4件套或drf的Response
return和raise完全不一样
视图类继承了
视图类:ViewSetMixin,ListModelMixin----》查询所有好多代码不用写----》可以自动生成路由
router.register('book',BookView,'book')
/book/--->get请求过来被映射了 list---》执行视图类中的list----》
BookView中写了get方法,根本不会执行
自动生成路由
继承了APIView,才有的---》执行流程---》dispatch中----》三大认证
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 # 这是个方法,包装成了数据属性
@property
def user(self):
if not hasattr(self, '_user'):
with wrap_attributeerrors():
self._authenticate()
return self._user
def _authenticate(self):
# self.authenticators 就是你写的认证类列表---》列表推导式---》[LoginAuth(),]
for authenticator in self.authenticators:
try:
user_auth_tuple = authenticator.authenticate(self)
except exceptions.APIException:
# 抛了异常被捕获了
if user_auth_tuple is not None:
# 如果返回了两个值,就会执行这句话
# self是Request的对象
self.user, self.auth = user_auth_tuple
return
self._not_authenticated()
APIView---》dispathc的前面
总结:
1 认证类,必须写一个方法authenticate
2 如果认证通过,可以返回None,也可也返回两个值,但是第一个值,尽量是当前登录用户,第二个值一般放token
3 认证失败,抛异常AuthenticationFailed,继承了APIException,他能捕获
只要做了国际化,会自动翻译成,当前国家的语言
from django.utils.translation import gettext_lazy as _
_('hello')
restful规范中
-请求地址中带过滤条件
带过滤的接口只有:查询所有
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin
from .models import Book
from rest_framework.filters import SearchFilter
# 内置过滤类
class BookView(GenericViewSet, ListModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer
# 支持这种搜索
# http://127.0.0.1:8000/api/v1/books/?search=红
# search_fields = ['name']
# http://127.0.0.1:8000/api/v1/books/?search=11 只要name或price中带11都能搜出来
filter_backends = [SearchFilter]
search_fields = ['name']
from django_filters.rest_framework import DjangoFilterBackend
第三方过滤类
class BookView(GenericViewSet, ListModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer
# 按名字和价格精准匹配
# http://127.0.0.1:8000/api/v1/books/?name=红楼梦&price=45
filter_backends = [DjangoFilterBackend]
filterset_fields = ['name', 'price']
views:
from .filter import MyFilter
自定义过滤类
class BookView(GenericViewSet, ListModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer
# 返回的数据,就是过滤后的数据
# http://127.0.0.1:8000/api/v1/books/?name=三国演义&price=25 按名字或价格
filter_backends = [MyFilter]
filterset_fields = ['name', 'price']
filter:
from rest_framework import filters
from django.db.models import Q
class MyFilter(filters.BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
price = request.query_params.get('price')
name = request.query_params.get('name')
# 返回的数据,就是过滤后的数据
# http://127.0.0.1:8000/api/v1/books/?price=44&name=红楼梦
# 按名字或价格
queryset = queryset.filter(Q(name=name) | Q(price=price))
return queryset
小练习:区间过滤
取出价格在100-200元之间的书
views:
# 自定义过滤价格在一百到两百之间的图书
from .filter import BookFilterSet
from rest_framework.filters import SearchFilter
class BookView(GenericViewSet, ListModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [BookFilterSet]
search_fields = ['price']
filter:
# 自定义过滤价格在一百到两百之间的图书
from rest_framework import filters
from .models import Book
class BookFilterSet(filters.BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
price = request.query_params.get('price')
min_price = request.query_params.get('min_price')
max_price = request.query_params.get('max_price')
queryset = queryset.filter(price__gt=min_price, price__lt=max_price)
return queryset
过滤和排序可以一起使用:
例:
url:
from django.contrib import admin
from django.urls import path, include
from rest_framework.routers import SimpleRouter
from app01 import views
router = SimpleRouter()
# 图书路由
# router.register('books', views.BookView, 'book')
# 出版社路由
# router.register('publishes', views.PublishView, 'publish')
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include(router.urls)),
]
views:
from .models import Publish
from .serializer import PublishSerializer
from rest_framework.filters import OrderingFilter
from .page import PublishPageNumberPagination
class PublishView(GenericViewSet, ListModelMixin):
queryset = Publish.objects.all()
serializer_class = PublishSerializer
filter_backends = [SearchFilter, OrderingFilter]
search_fields = ['title', 'addr']
ordering_fields = ['id']
pagination_class = PublishPageNumberPagination
page:
class PublishPageNumberPagination(PageNumberPagination):
page_size = 1
page_size_query_param = 'page_size'
page_query_param = 'page'
max_page_size = 5
restful规范中
-请求地址中带过滤条件
排序功能的接口:查询所有
排序
from rest_framework.filters import OrderingFilter
class BookView(GenericViewSet, ListModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer
# 排序类
# http://127.0.0.1:8000/api/v1/books/?ordering=price
filter_backends = [OrderingFilter]
ordering_fields = ['price']
查询所有接口,过滤和排序了,但是实际上,这个接口,都需要有分页功能
-分页的展现形式
web:下一页点解
app,小程序:下滑下一页
-接口都一样,要支持分页
drf提供给咱们,三种分页方式:
1.基本分页(用的较多)
views:
class BookView(GenericViewSet, ListModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer
# 基本分页
# http://127.0.0.1:8000/api/v1/books/?page=2&page_size=3
pagination_class = MyPageNumberPagination # 基本分页
page:
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination
# 基本分页
class MyPageNumberPagination(PageNumberPagination):
# 重新几个类属性 :4个
page_size = 2 # 每页的显示条数
page_query_param = 'page' # page=4表示第4页
page_size_query_param = 'page_size' # page=4&page_size=5 表示查询第4页,每页显示5条
max_page_size = 5 # 每页最大显示多少条
2.偏移分页
view:
# 偏移分页
# http://127.0.0.1:8000/api/v1/books/?limit=2&offset=5
pagination_class = MYLimitOffsetPagination
page:
# 偏移分页
class MYLimitOffsetPagination(LimitOffsetPagination):
# 重写几个类属性:4个
default_limit = 2 # 每页显示多少条
limit_query_param = 'limit' # limit=3 这一页取三条
offset_query_param = 'offset' # 偏移量是多少 offset=3
max_limit = 5 # 最多取5条
3.游标分页
views:
# 游标分页
# http://127.0.0.1:8000/api/v1/books/?ordering=id
pagination_class = MyCursorPagination
page:
# 游标分页
class MyCursorPagination(CursorPagination):
# 重写三个类属性
cursor_query_param = 'cursor' # 查询参数其实用不到
page_size = 2 # 每页显示多少条
ordering = 'id' # 必须是要分页的数据表中的字段,一般按id来分