商品列表页、详情页功能实现


打造生鲜超市(一):项目介绍,环境搭建
打造生鲜超市(二):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

django_filters

# 官方文档: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

三、商品详情页

打造生鲜超市(七):商品详情页功能

相关blog

相似问题

 

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

UniqueTogetherValidator

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")

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2024 CODEPRJ.COM