打造生鲜超市(一):项目介绍,环境搭建
打造生鲜超市(二):model设计
打造生鲜超市(三):xadmin后台管理
打造生鲜超市(四):商品列表页
打造生鲜超市(五):商品类别数据显示
一、商品列表页
1、 goods/serializers.py 序列化
from rest_framework import serializers from goods.models import GoodsCategory class CategorySerializer3(serializers.ModelSerializer): '''三级分类''' class Meta: model = GoodsCategory fields = "__all__" class CategorySerializer2(serializers.ModelSerializer): '''二级分类''' sub_cat = CategorySerializer3(many=True) class Meta: model = GoodsCategory fields = "__all__" # class CategorySerializer(serializers.ModelSerializer): '''一级分类''' sub_cat = CategorySerializer2(many=True) class Meta: model = GoodsCategory fields = "__all__"
class GoodsSerializer(serializers.ModelSerializer): category = CategorySerializer() #覆盖默认的category序列化字段 images = GoodsImageSerializer(many=True) # images名称是GoodsImage中goods = models.ForeignKey(Goods, verbose_name="商品", related_name="images") # related_name="images" 中的images class Meta: model = Goods fields = "__all__" # 取所有字段
2、goods/filter
# 官方文档:https://django-filter.readthedocs.io/en/stable/guide/rest_framework.html#quickstart import django_filters from django.db.models import Q from .models import Goods class GoodsFilter(django_filters.rest_framework.FilterSet): """ 商品的过滤类 """ # 自从 django-filter2.0之后 将Filter的name字段 更名为 field_name(本项目用的django-filter2.3) pricemin = django_filters.NumberFilter(field_name='shop_price', help_text="最低价格",lookup_expr='gte') pricemax = django_filters.NumberFilter(field_name='shop_price', lookup_expr='lte') top_category = django_filters.NumberFilter(method='top_category_filter') # def top_category_filter(self, queryset, name, value): return queryset.filter(Q(category_id=value)|Q(category__parent_category_id=value)|Q(category__parent_category__parent_category_id=value)) # class Meta: model = Goods fields = ['pricemin', 'pricemax', 'is_hot', 'is_new']
3、goods/views.py
from .serializers import GoodsSerializer, CategorySerializer, HotWordsSerializer, BannerSerializer from rest_framework import mixins from rest_framework import filters from rest_framework.pagination import PageNumberPagination from django_filters.rest_framework import DjangoFilterBackend from rest_framework import viewsets # .models:加 . 的好处表示从当前的goods目录下找models,加速查找且不容易找失败 from .models import Goods, GoodsCategory from .filters import GoodsFilter # 自定义分页 class GoodsPagination(PageNumberPagination): page_size = 12 # 每一页显示多少条数据 page_query_param = "page" # url中指定显示哪一页的数据 ?page=2 page_size_query_param = 'page_size' # 临时控制每页显示几条数据 ?page=2&page_size=2 max_page_size = 100 # 每页最多显示多少条数据,针对上面的size class GoodsListViewSet(mixins.ListModelMixin,mixins.RetrieveModelMixin, viewsets.GenericViewSet): """ 商品列表页, 分页, 搜索, 过滤, 排序 """ queryset = Goods.objects.all()# serializer_class = GoodsSerializer# pagination_class = GoodsPagination# # authentication_classes = (TokenAuthentication, ) # 商品列表页是公开的,不需要授权认证 filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter)# filter_class = GoodsFilter# search_fields = ('name', 'goods_brief', 'goods_desc')# ordering_fields = ('sold_num', 'shop_price')# # class CategoryViewset(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet): """ list: 商品分类列表数据 retrieve: 获取商品分类详情 """ queryset = GoodsCategory.objects.filter(category_type=1) # 获取第一类数据 serializer_class = CategorySerializer
4、urls.py
# 配置Category的url router.register(r'categorys', CategoryViewSet, base_name="categorys")
二、drf跨域问题
后端服务器解决跨域问题的方法
1、安装模块django-cors-headers
pip install django-cors-headers
2、 添加到INSTALL_APPS中
INSTALLED_APPS = ( ...
'coreschema',
... )
3、添加中间件
必须在CsrfViewMiddleware之前。我们直接放在第一个位置就好了
4、settings中相关设置
CORS_ORIGIN_ALLOW_ALL = True
三、商品详情页
打造生鲜超市(七):商品详情页功能
1、商品轮播图goods/serializers.py
from rest_framework import serializers from goods.models import Goods, GoodsImage # 商品详情页轮播图 class GoodsImageSerializer(serializers.ModelSerializer): class Meta: model = GoodsImage fields = ("image", ) class GoodsSerializer(serializers.ModelSerializer): category = CategorySerializer() #覆盖默认的category序列化字段 images = GoodsImageSerializer(many=True) # images名称是GoodsImage中goods = models.ForeignKey(Goods, verbose_name="商品", related_name="images") # related_name="images" 中的images class Meta: model = Goods fields = "__all__" # 取所有字段
2、热销商品
只需要在过滤器中增加“is_hot”就可以了
goods/filters.py里的GoodsFilter添加“is_hot”
class Meta: model = Goods fields = ['pricemin', 'pricemax','is_hot']
3、用户收藏
CurrentUserDefault
Custom permissions:Examples
Attributes:lookup_field
HiddenField:
HiddenField的值不依靠输入,而需要设置默认的值,不需要用户自己post数据过来,也不会显式返回给用户,最常用的就是user!!
我们在收藏某件商品的时候,后台要获取到当前的用户;相当于前台只需要传递过来一个商品的ID即可;
那么在后台我根据当前的登入用户和当前的商品ID即可判断用户是否收藏过该商品;这就是一个联合唯一主键的判断;这同样需要使用HiddenField。
(1)序列化
user_operation/serializers.py
from rest_framework import serializers from user_operation.models import UserFav from rest_framework.validators import UniqueTogetherValidator class UserFavSerializer(serializers.ModelSerializer): #获取当前登录的用户 user = serializers.HiddenField( default=serializers.CurrentUserDefault() ) class Meta: #validate实现唯一联合,一个商品只能收藏一次 validators = [ UniqueTogetherValidator( queryset=UserFav.objects.all(), fields=('user', 'goods'), #message的信息可以自定义 message="已经收藏" ) ] model = UserFav #收藏的时候需要返回商品的id,因为取消收藏的时候必须知道商品的id是多少 fields = ("user", "goods",'id')
(2)user_operation/views.py
from rest_framework import viewsets from rest_framework import mixins from rest_framework.permissions import IsAuthenticated from rest_framework_jwt.authentication import JSONWebTokenAuthentication from rest_framework.authentication import SessionAuthentication from .models import UserFav, UserLeavingMessage, UserAddress from utils.permissions import IsOwnerOrReadOnly from .serializers import UserFavSerializer, UserFavDetailSerializer, AddressSerializer, LeavingMessageSerializer class UserFavViewset(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.DestroyModelMixin, viewsets.GenericViewSet): """ list: 获取用户收藏列表 retrieve: 判断某个商品是否已经收藏 create: 收藏商品
destory:
取消收藏 """ # queryset = UserFav.objects.all() # 不能获取所有人的UserFav serializer_class = UserFavSerializer # IsAuthenticated:用户必须登录,IsOwnerOrReadOnly:必须是当前的用户在操作 permission_classes = (IsAuthenticated, IsOwnerOrReadOnly) # auth使用来做用户认证的 authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication) # 搜索的字段 lookup_field = "goods_id" # 获取当前用户的 UserFav def get_queryset(self): return UserFav.objects.filter(user=self.request.user)
(3)配置url
# 配置用户收藏的url router.register(r'userfavs', UserFavViewset, base_name="userfavs")