打造生鮮超市(一):項目介紹,環境搭建
打造生鮮超市(二):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")