session的执行流程
写一个登录接口----->保存用户的登录状态
-获取到用户名,密码
-使用request.session["username"] = 用户名、或者request.session["pk"] = pk值
-签发阶段做了三件事:
-1、生成一个随机的字符串
-2、在django_session表中保存
-session_key:随机字符串
-session_data:加密后的数据
-expire_data:截止到14天后到期自动删除
-3、把随机的字符串以cookie形式返回给前端(存在浏览器的cookie中)
-认证阶段:
-1、取出在cookie中session_id对应的随机字符串
-2、通过这个随机字符串在django_session表中查询,如果查询的到说明该用户是在登录状态
-3、将session_data的数据放到request_session中
过滤
只针对于,查询所有接口,必须要继承 GenericAPIView
安装:
-pip install django==3.2.12
-pip install django-filter
使用方法
方法一:内置的、模糊匹配
from rest_framework.filters import SearchFilter
# 重写属性
filter_backends = [SearchFilter, OrderingFilter]
search_fields = ['name', 'price']
# 查询方式
http://127.0.0.1:8000/text/?search=水 # 就可以查出来与水相关的书籍
方式二:第三方的、精准匹配而且支持"&"
from django_filters.rest_framework import DjangoFilterBackend
# 重写属性
filter_backends = [DjangoFilterBackend]
filterset_fields = ["name", "price"]
# 查询方式:
http://127.0.0.1:8000/text/?name=红楼梦 or
http://127.0.0.1:8000/text/?name=红楼梦&price=123
方式三:自定义方法
# 重写属性
filter_backends = [BookFilter]
# 查询方式
http://127.0.0.1:8000/books/?price=123&name=西游记
自定义过滤方法
from rest_framework.filters import BaseFilterBackend
class BookFilter(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
search_parm = request.query_params.get("name")
search_price = request.query_params.get("price")
print("++++", search_parm, "-----", search_price)
if search_parm and search_price:
print("走到这里了")
queryset = queryset.filter(name__contains=search_parm, price=search_price)
return queryset
继承ViewSet实现的视图
class BookText(ViewSet):
def list(self, request):
# 获取到前端传入的筛选条件
search_parm = request.query_params.get("name")
# 通过__contains找到与我这个name字段是否有我search_parm的值,如果有返回这个值的对象
book_obj = Book.objects.all().filter(name__contains=search_parm)
serializers = BookSerializers(instance=book_obj, many=True)
return Response(serializers.data)
继承GenericAPIView写过滤类,可以写多个
# 写多个,他们是从左往右,依次执行
# 大原则,配置多个过滤类的时候,第一个放尽量多个过滤掉数据
# 配置多个:执行原理
-先执行第一个过滤类的:filter_queryset返回qs对象
-再执行第二个过滤类的filter_queryset,传入上一个返回的qs,过滤完返回qs对象
过滤小结
1、内置的:from rest_framework.filters import SearchFilter
-重写属性:
-filter_backends、search_fields
2、第三方的:from django_filters.rest_framework import DjangoFilterBackend
-重写属性:
-filter_backends、filterset_fields
3、自定义的:from rest_framework.filters import BaseFilterBackend
-自己写一个类继承BaseFilterBackend,可以按照自己的想法,指定想要过滤的字段
-重写属性:
-filter_backends
分类
只针对于查询所有接口:
-分页展示形式
web:上一页,下一页
小程序:上拉加载更多
必须继承 GenericAPIView
三种分页方式------->drf提供的
导入模块:
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination
class ComePageNumber(PageNumberPagination):
# 重写参数
page_size = 3 # 每页展示3条
page_query_parm = "page" # 索引前缀
page_size_query_param = "size" # # 可以指定每页显示多少条 eg:size=300000
max_page_size = 4
前端展示
{
"count": 4, # 总数据量
"next": "http://127.0.0.1:8000/text/?page=2", # 下一页
"previous": null, # 前一页
"results": [
{
"id": 1,
"name": "西游记",
"price": "123"
},
{
"id": 2,
"name": "红楼梦",
"price": "234"
},
{
"id": 3,
"name": "红楼梦",
"price": "345"
}
]
}
class ComeLimit(LimitOffsetPagination):
default_limit = 2 # 默认每页显示2条
limit_query_param = "limit" # 每页显示多少条的查询
offset_query_param = "offset" # 从第几条数据开始
max_limit = 5 # limit最多取5条
前端展示
URLs:
http://127.0.0.1:8000/text/?limit=3&offset=3&size=2
{
"count": 4,
"next": null,
"previous": "http://127.0.0.1:8000/text/?limit=3&size=2",
"results": [
{
"id": 4,
"name": "水浒传",
"price": "456"
}
]
}
class ComeCursor(CursorPagination):
cursor_query_param = "cursor"
page_size = 2
ordering = "id"
前端展示
URLs:
http://127.0.0.1:8000/text/?cursor=cj0xJnA9Mw%3D%3D
{
"next": "http://127.0.0.1:8000/text/?cursor=cD0y",
"previous": null,
"results": [
{
"id": 1,
"name": "西游记",
"price": "123"
},
{
"id": 2,
"name": "红楼梦",
"price": "234"
}
]
}
分页类总结
继承PageNumberPagination分页类:
-重写属性:
-page_size = 4 # 每页显示4条
-page_query_parm = "page" # 索引前缀
-page_size_query_param = "size" # 可以指定每页显示多少条 eg:size=300
-max_page_size = 4
继承LimitOffsetPagination分页类:
-重写属性:
-default_limit = 2 # 默认每页显示2条
-limit_query_param = "limit" # 每页显示多少条的查询
-offset_query_param = "offset" # 从第几条数据开始
-max_limit = 5 # limit最多取5条
继承CursorPagination分页类:
-重写属性:
-cursor_query_param = "cursor"
-page_size = 2
-ordering = "id"
PageNumberPagination适用于传统的分页需求,简单易用,但在大数据量和实时数据更新的场景下性能可能有限。
LimitOffsetPagination适用于快速定位到某个位置的场景,但在大数据量和实时数据更新的场景下性能可能有限。
CursorPagination适用于大数据量和实时数据更新的场景,可以灵活定制排序方式,但需要客户端保存和传递游标信息
继承GenericAPIView实现的视图
class Text(ViewSetMixin, ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializers
################分页类################
pagination_class = ComeCursor
pagination_class = ComeLimit
pagination_class = ComePageNumber
# 三者选其一即可,前提是三个分页类都写好了
#####################################
filter_backends = [DjangoFilterBackend]
filterset_fields = ["name", "price"]
继承APIView实现
异常处理
# drf中的所有异常都会被全局捕捉到
-认证类,认证不通过抛出异常,会被全局捕捉到,所以前端不会崩掉,只会得到错误信息
drf全局异常处理,他会把drf的异常处理掉,统一返回格式,但是django原生的和python的都不会处理
# 我们要做的就是无论是Python还是Django异常我们都可以捕捉到,统一格式返回
新建一个exception文件
1、写一个方法;
from rest_framework.views import exception_handler
from rest_framework.response import Response
def my_exception(exc, context):
exc = exception_handler(exc, context) # 返回结果为None
if not exc: # 如果不为None就除drf的异常
return Response({'code': 1000, 'msg': '非drf错误,错误信息是:%s' % str(exc)})
else: # 否则就是drf的异常
return Response({'code': 1000, 'msg': 'drf错误,错误信息是:' + exc.data.get('detail')})
2 配置文件配置
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'app01.exceptions.common_exception', # 以后只要出了异常,都会走这个函数
}
补充
1 DateField、DateTimeField
-auto_now_add=True # 创建数据时自动添加当前时间
-auto_now=True # 每次操作数据时更新为当前时间