Django+Vue打造購物網站(十)
首頁、商品數量、快取和限速功能開發
將環境切換為本地,vue也切換為本地
輪播圖
goods/serializers.py
class BannerSerializer(serializers.ModelSerializer):
'''
輪播圖
'''
class Meta:
model = Banner
fields = "__all__"
goods/views.py
class BannerViewset(mixins.ListModelMixin, viewsets.GenericViewSet): """ 首頁輪播圖 """ queryset = Banner.objects.all().order_by("index") serializer_class = BannerSerializer
urls.py
# 配置首頁輪播圖的url
router.register(r'banners', BannerViewset, base_name="banners")
新品推薦功能
在設計Goods model時候有一個欄位is_new
is_new = models.BooleanField(default=False, verbose_name="是否新品")
實現這個介面只要在goods/filters/GoodsFilter裡面新增一個過濾就可以了
class Meta: model = Goods fields = ['pricemin', 'pricemax','is_hot','is_new']
首頁商品分類顯示功能
goods/serializers.py
class BrandSerializer(serializers.ModelSerializer): ''' 大類下面的宣傳商標 ''' class Meta: model = GoodsCategoryBrand fields = "__all__" class IndexCategorySerializer(serializers.ModelSerializer): # 某個大類的商標,可以有多個商標,一對多的關係 brands = BrandSerializer(many=True) # good有一個外來鍵category,但這個外來鍵指向的是三級類,直接反向通過外來鍵category(三級類),取某個大類下面的商品是取不出來的 goods = serializers.SerializerMethodField() # 在parent_category欄位中定義的related_name="sub_cat" # 取二級商品分類 sub_cat = CategorySerializer2(many=True) # 廣告商品 ad_goods = serializers.SerializerMethodField() def get_ad_goods(self, obj): goods_json = {} ad_goods = IndexAd.objects.filter(category_id=obj.id, ) if ad_goods: # 取到這個商品Queryset[0] good_ins = ad_goods[0].goods # 在serializer裡面呼叫serializer的話,就要新增一個引數context(上下文request), # 否則圖片連結是不完整的 # 巢狀serializer必須加 # serializer返回的時候一定要加 “.data” ,這樣才是json資料 goods_json = GoodsSerializer(good_ins, many=False, context={'request': self.context['request']}).data return goods_json # 自定義獲取方法 def get_goods(self, obj): # 將這個商品相關父類子類等都可以進行匹配 all_goods = Goods.objects.filter(Q(category_id=obj.id) | Q(category__parent_category_id=obj.id) | Q( category__parent_category__parent_category_id=obj.id)) goods_serializer = GoodsSerializer(all_goods, many=True, context={'request': self.context['request']}) return goods_serializer.data class Meta: model = GoodsCategory fields = "__all__"
goods/views.py
class IndexCategoryViewset(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
首頁商品分類資料
"""
# 獲取is_tab=True(導航欄)裡面的分類下的商品資料
queryset = GoodsCategory.objects.filter(is_tab=True, name__in=["生鮮食品", "酒水飲料"])
serializer_class = IndexCategorySerializer
urls.py
# 首頁系列商品展示url
router.register(r'indexgoods', IndexCategoryViewset, base_name="indexgoods")
熱搜詞
goods/serializers.py
class HotWordsSerializer(serializers.ModelSerializer):
class Meta:
model = HotSearchWords
fields = "__all__"
goods/views.py
class HotSearchsViewset(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
獲取熱搜詞列表
"""
queryset = HotSearchWords.objects.all().order_by("-index")
serializer_class = HotWordsSerializer
urls.py
# 首頁熱搜詞
router.register(r'hotsearchs', HotSearchsViewset, base_name="hotsearchs")
商品點選數和收藏數
GoodsListViewSet其中繼承了mixins.RetrieveModelMixin
只需要重寫retrieve
方法即可
class GoodsListViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
'''
商品列表頁, 分頁, 過濾, 排序
'''
queryset = Goods.objects.all().order_by('id')
serializer_class = GoodsSerializer
pagination_class = GoodsPagination
filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter)
# authentication_classes = (TokenAuthentication,)
# 自定義過濾器
filter_class = GoodsFilter
# 搜尋,預設模糊查詢
search_fields = ('name', 'goods_brief')
# 排序
ordering_fields = ('sold_num', 'shop_price')
# 商品點選數 + 1
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)
UserFavViewset繼承了mixins.CreateModelMixin
重寫perform_create
方法即可
class UserFavViewset(viewsets.GenericViewSet, mixins.ListModelMixin, mixins.CreateModelMixin, mixins.DestroyModelMixin):
'''
list:
獲取使用者的所有收藏
create:
新增收藏
destroy:
取消收藏
'''
# permission是用來做許可權判斷的
# IsAuthenticated:必須登入使用者;IsOwnerOrReadOnly:必須是當前登入的使用者
permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
# auth使用來做使用者認證的
authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
# 搜尋的欄位
lookup_field = 'goods_id'
def get_queryset(self):
# 只能檢視當前登入使用者的收藏,不會獲取所有使用者的收藏
return UserFav.objects.filter(user=self.request.user)
# 動態選擇serializer
def get_serializer_class(self):
if self.action == "list":
return UserFavDetailSerializer
elif self.action == "create":
return UserFavSerializer
return UserFavSerializer
# 使用者收藏的商品數量+1
def perform_create(self, serializer):
instance = serializer.save()
# 這裡instance相當於UserFav model,通過它找到goods
goods = instance.goods
goods.fav_num += 1
goods.save()
用訊號量實現收藏數變化
delete和create的時候django model都會發送一個訊號量出來,用訊號量的方式程式碼分離性更好
user_operation/signals.py
from django.db.models.signals import post_delete, post_save
from django.dispatch import receiver
from user_operation.models import UserFav
# post_save : model變化方式
# sender : 變動的model
@receiver(post_save, sender=UserFav)
def create_userfav(sender, instance=None, created=False, **kwargs):
if created:
goods = instance.goods
goods.fav_num += 1
goods.save()
@receiver(post_delete, sender=UserFav)
def delete_userfav(sender, instance=None, created=False, **kwargs):
goods = instance.goods
goods.fav_num -= 1
goods.save()
user_operation/apps.py
from django.apps import AppConfig
class UserOperationConfig(AppConfig):
name = 'user_operation'
verbose_name = "使用者操作管理"
def ready(self):
import user_operation.signals
商品庫存和銷量修改
引起商品庫存數量變化的行為:
- 新增商品到購物車
- 修改購物車數量
- 刪除購物車記錄
trade/views.py
class ShoppingCartViewset(viewsets.ModelViewSet):
"""
購物車功能
list:
獲取購物車詳情
create:
加入購物車
delete:
刪除購物記錄
"""
permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
# serializer_class = ShopCartSerializer
lookup_field = "goods_id"
def get_queryset(self):
return ShoppingCart.objects.filter(user=self.request.user)
def get_serializer_class(self):
if self.action == 'list':
return ShopCartDetailSerializer
else:
return ShopCartSerializer
# 庫存數-n
def perform_create(self, serializer):
shop_cart = serializer.save()
goods = shop_cart.goods
goods.goods_num -= shop_cart.nums
goods.save()
# 庫存數+n
def perform_destroy(self, instance):
goods = instance.goods
goods.goods_num += instance.nums
goods.save()
instance.delete()
# 更新庫存,修改可能是增加頁可能是減少
def perform_update(self, serializer):
# 首先獲取修改之前的庫存數量
existed_record = ShoppingCart.objects.get(id=serializer.instance.id)
existed_nums = existed_record.nums
# 先儲存之前的資料existed_nums
saved_record = serializer.save()
# 變化的數量
nums = saved_record.nums - existed_nums
goods = saved_record.goods
goods.goods_num -= nums
goods.save()
商品的銷量只有在支付成功後才會 +n
trade/views.py
AlipayView/post方法
# 查詢資料庫中訂單記錄
existed_orders = OrderInfo.objects.filter(order_sn=order_sn)
for existed_order in existed_orders:
# 訂單商品項
order_goods = existed_order.goods.all()
# 商品銷量增加訂單中數值
for order_good in order_goods:
goods = order_good.goods
goods.sold_num += order_good.goods_num
goods.save()
# 更新訂單狀態
existed_order.pay_status = trade_status
existed_order.trade_no = trade_no
existed_order.pay_time = datetime.now()
existed_order.save()
# 需要返回一個'success'給支付寶,如果不返回,支付寶會一直髮送訂單支付成功的訊息
return Response("success")
drf快取
http://chibisov.github.io/drf-extensions/docs/#caching
pip install drf-extensions
簡單使用
在GoodsListViewSet中新增快取功能
from rest_framework_extensions.cache.mixins import CacheResponseMixin
# CacheResponseMixin一定要放在第一個位置
class GoodsListViewSet(CacheResponseMixin,mixins.ListModelMixin, mixins.RetrieveModelMixin,viewsets.GenericViewSet):
設定過期時間,settings裡面
# 快取配置
REST_FRAMEWORK_EXTENSIONS = {
'DEFAULT_CACHE_RESPONSE_TIMEOUT': 60*60*8 # 多少秒過期,時間自己可以隨便設定
}
這個快取使用的是記憶體,每次重啟之後就會失效
drf配置redis快取
https://django-redis-chs.readthedocs.io/zh_CN/latest/
drf的throttle設定api的訪問速率
針對爬蟲
http://www.django-rest-framework.org/api-guide/throttling/
settings中配置
REST_FRAMEWORK = {
# 限速設定
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.AnonRateThrottle', # 未登陸使用者
'rest_framework.throttling.UserRateThrottle' # 登陸使用者
),
'DEFAULT_THROTTLE_RATES': {
'anon': '10/minute', # 每分鐘可以請求n次
'user': '30/minute' # 每分鐘可以請求n次
}
}
goods/views.py中使用
from rest_framework.throttling import UserRateThrottle,AnonRateThrottle
class GoodsListViewSet(CacheResponseMixin,mixins.ListModelMixin, mixins.RetrieveModelMixin,viewsets.GenericViewSet):
.
.
throttle_classes = (UserRateThrottle, AnonRateThrottle)