class GoodsListViewSet(CacheResponseMixin,mixins.ListModelMixin,mixins.RetrieveModelMixin,viewsets.GenericViewSet):
'''
商品列表页
'''
queryset = Goods.objects.all()
serializer_class = GoodsSerializer
pagination_class = GoodsPagination
# authentication_classes = (TokenAuthentication,)
# def get_queryset(self):
# queryset = Goods.objects.all() # 只有for时才会执行
# price_min = self.request.query_params.get("price_min",0)
# if price_min:
# queryset = queryset.filter(shop_price__gt=int(price_min))
# return queryset
# 精确过滤:根据字段过滤
filter_backends = (DjangoFilterBackend,filters.SearchFilter,filters.OrderingFilter)
# filter_fields = ('name', 'shop_price')
# 搜索功能 ^表示name必须匹配开头
search_fields = ('name', 'good_brief', 'good_desc')
# 排序
ordering_fields = ('shop_price','sold_num')
# 条件筛选
filter_class = GoodsFilter
throttle_classes = (UserRateThrottle, AnonRateThrottle)
"""
Retrieve a model instance.
"""
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
instance.click_num += 1
instance.save()
serializer = self.get_serializer(instance)
return Response(serializer.data)
查询结果集
获取查询结果集,如果重写了此方法,则默认忽略queryset
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 10,
}
class GoodsPagination(PageNumberPagination):
page_size = 12 # 默认每页显示的数据条数
page_size_query_param = 'page_size' # 获取url参数中设置的每页显示数据条数
page_query_param = "page" # 获取url中传入的页码key
max_page_size = 60 # 最大支持的每页显示的数据条数
https://www.cnblogs.com/haiyan123/p/8433233.html
class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):
'''
商品列表页
'''
queryset = Goods.objects.all()
serializer_class = GoodsSerializer
pagination_class = GoodsPagination
def get_queryset(self):
queryset = Goods.objects.all() # 只有for时才会执行
price_min = self.request.query_params.get("price_min",0)
if price_min:
queryset = queryset.filter(shop_price__gt=int(price_min))
return queryset
1.精确过滤(根据字段完全匹配)
class GoodsListViewSet(mixins.ListModelMixin,viewsets.GenericViewSet):
'''
商品列表页
'''
queryset = Goods.objects.all()
serializer_class = GoodsSerializer
pagination_class = GoodsPagination
# 精确过滤:根据字段过滤
filter_backends = (DjangoFilterBackend,)
filter_fields = ('name', 'shop_price')
2.添加筛选条件(模糊查询,范围查询…)
class GoodsFilter(filters.FilterSet):
'''
商品的过滤类
'''
# field_name要配置的字段 lookup_expr 要满足的条件
min_price = filters.NumberFilter(field_name="shop_price", lookup_expr='gte')
max_price = filters.NumberFilter(field_name="shop_price", lookup_expr='lte')
# contains 模糊查询(like) i忽略大小写
name = filters.CharFilter(field_name="name", lookup_expr='icontains')
class Meta:
model = Goods
fields = ['min_price', 'max_price', 'name']
top_category = filters.NumberFilter(method='top_category_filter')
def top_category_filter(self,queryset,name,value):
# category是外键 category_id找到对应的外键表的id(其实category_id是在数据库中保存的外键名)
# category_id = 3 就是找类别为3的所有商品
# parent_category_id是外键表自关联的外键,
# category__parent_category_id=2就是找parent_category_id=2的所有category,
# 然后再找属于这些category下面的所有goods
# 或者说goods外键表中的parent_category_id=2等于二的goods
# category__parent_category__parent_category_id=1
# 就是找 goods所关联的category的所关联的parent_category中的parent_category_id为1的所有goods
# goods对应的category是三级,可以通过这个category自身的parent_category_id找到所有的二级所对应的id
# 或者通过parent_category找到所有的二级对象,而二级对象又可以通过parent_category_id找到所有的三级的id
# 双下划线表示引出这个对象下所对应的某个值
return queryset.filter(Q(category_id=value)|Q(category__parent_category_id=value)
|Q(category__parent_category__parent_category_id=value))
配置到filter_class
# 精确过滤:根据字段过滤
filter_backends = (DjangoFilterBackend,)
# filter_fields = ('name', 'shop_price')
# 条件筛选
filter_class = GoodsFilter
# 搜索功能 ^表示name必须匹配开头
search_fields = ('^name', 'good_brief', 'good_desc')
# 精确过滤:根据字段过滤
filter_backends = (DjangoFilterBackend,filters.SearchFilter,filters.OrderingFilter)
# 排序
ordering_fields = ('market_price','sold_num')
serializer_class = GoodsSerializer
这个类的设置主要是为了使用token或者session验证方式获取用户信息,只有permission才会做真正的拦截处理
views
# 设置JSONWebTokenAuthentication为局部,让用户访问Goods列表时不做登录限制
# 设置SessionAuthentication,让已登录用户访问收藏列表时不会提示用户认证未提供,方便开发时的调试(因为调试时,往往不会讲token放到header中),
# 这个类的设置主要是为了使用token或者session验证方式获取用户信息,然后交给permission验证
authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
栗子:让用户只能对自己的收藏列表进行操作
# IsAuthenticated 判断是否登录,
# 只有已经登录的用户才能获取到个人信息
# 未登录,返回 401 "detail": "Authentication credentials were not provided."
# IsOwnerOrReadOnly 让用户只能对自己的收藏列表进行操作
# 如果没有权限,则抛出404,找不到
permission_classes = (IsAuthenticated,IsOwnerOrReadOnly)
自己定义的permission类
permissions.py
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Object-level permission to only allow owners of an object to edit it.
Assumes the model instance has an `owner` attribute.
"""
def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request,
# so we'll always allow GET, HEAD or OPTIONS requests.
if request.method in permissions.SAFE_METHODS:
return True
# Instance must have an attribute named `owner`.
# obj就是数据库中查出来的那个对象
return obj.user == request.user
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
request也可以直接通过self点出来
def perform_create(self, serializer):
return serializer.save()
一般要保存对象需要做额外操作时重写
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = self.perform_create(serializer)
# 这一步会序列化对象,所有fields中的字段都会被序列号,而code已经被删除了
# ,所以code中加入了write_only=True,让他不要被序列化和返回前端
# register的用户对象
re_dict = serializer.data
# 将token返回给前端
payload = jwt_payload_handler(user)
re_dict["token"] = jwt_encode_handler(payload)
re_dict["name"] = user.name if user.name else user.username
headers = self.get_success_headers(serializer.data)
return Response(re_dict, status=status.HTTP_201_CREATED, headers=headers)
执行保存对象的操作,被create地调用,一般和信号量配合使用
# 重写次方法,返回user
def perform_create(self, serializer):
# 这里需要操作数据库,而密码需要加密,所以用到了信号量
# 在每次post保存的时候,将密码加密
return serializer.save()
设置retrieve的查询字段是goods_id,而不是表中的默认主键id
lookup_field = “goods_id” # 因为goods是外键,所有加下划线
lookup_field是在get_queryset进行筛选之后执行的,因此不用担心查到其他不属于当前用户的good
查询或删除的url
http://127.0.0.1:8000/userfavs/16/ 16为goods_id
获取根据filter_kwargs再次queryset中查找匹配的一个QuerySet实例,查不到返回404,查到多个抛出异常
源码
filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
obj = get_object_or_404(queryset, **filter_kwargs)
try:
return queryset.get(*args, **kwargs)
except queryset.model.DoesNotExist:
raise Http404('No %s matches the given query.' % queryset.model._meta.object_name)
此处重写该方法,是为了直接返回后端定位到的当前的user,而不用前端去手动的传值查询
# 当Update和Retrieve和Destroy的时候都会用到该方法
def get_object(self):
return self.request.user
栗子:本处,添加收藏时,序列化当前用户
获取收藏时,返回goods的序列化结果
def get_serializer_class(self):
if self.action == "list":
return UserFavDetailSerializer
elif self.action == "create":
return UserFavSerializer
return UserFavSerializer
栗子:本处,创建用户时,不要求验证是否已经登录,其他操作,如更新,获取个人信息都需要验证
def get_permissions(self):
if self.action == "retrieve":
return [permissions.IsAuthenticated()]
elif self.action == "create":
return []
return []
# 重写get_queryset,只返回当前用户的收藏信息
def get_queryset(self):
return UserFav.objects.filter(user=self.request.user)
def perform_destroy(self, instance):
goods = instance.goods
goods.goods_num += instance.nums
goods.save()
instance.delete()
def perform_update(self, serializer):
# 修改商品的库存,通过比对购物车更新前后该商品的数量
# newstorage = oldstorage + (after-before)
existed_record = ShoppingCart.objects.get(id=serializer.instance.id)
existed_nums = existed_record.nums
saved_record = serializer.save()
nums = saved_record.nums-existed_nums
goods = saved_record.goods
goods.goods_num -= nums
goods.save()
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
instance.click_num += 1
instance.save()
serializer = self.get_serializer(instance)
return Response(serializer.data)