商品詳情頁


商品詳情頁依然采用頁面靜態化技術。

商品詳情頁的靜態化由運營人員在編輯商品信息時觸發生成靜態化頁面。

先來實現靜態化異步任務,在celery_tasks中新建html/tasks.py任務

from celery_tasks.main import app from django.template import loader from django.conf import settings import os from goods.utils import get_categories from goods.models import SKU @app.task(name='generate_static_sku_detail_html') def generate_static_sku_detail_html(sku_id): """ 生成靜態商品詳情頁面 :param sku_id: 商品sku id """ # 商品分類菜單 categories = get_categories() # 獲取當前sku的信息 sku = SKU.objects.get(id=sku_id) sku.images = sku.skuimage_set.all() # 面包屑導航信息中的頻道 goods = sku.goods goods.channel = goods.category1.goodschannel_set.all()[0] # 構建當前商品的規格鍵 # sku_key = [規格1參數id, 規格2參數id, 規格3參數id, ...] sku_specs = sku.skuspecification_set.order_by('spec_id') sku_key = [] for spec in sku_specs: sku_key.append(spec.option.id) # 獲取當前商品的所有SKU skus = goods.sku_set.all() # 構建不同規格參數(選項)的sku字典 # spec_sku_map = { # (規格1參數id, 規格2參數id, 規格3參數id, ...): sku_id, # (規格1參數id, 規格2參數id, 規格3參數id, ...): sku_id, # ... # } spec_sku_map = {} for s in skus: # 獲取sku的規格參數 s_specs = s.skuspecification_set.order_by('spec_id') # 用於形成規格參數-sku字典的鍵 key = [] for spec in s_specs: key.append(spec.option.id) # 向規格參數-sku字典添加記錄 spec_sku_map[tuple(key)] = s.id # 獲取當前商品的規格信息 #specs = [ # { # 'name': '屏幕尺寸', # 'options': [ # {'value': '13.3寸', 'sku_id': xxx}, # {'value': '15.4寸', 'sku_id': xxx}, # ] # }, # { # 'name': '顏色', # 'options': [ # {'value': '銀色', 'sku_id': xxx}, # {'value': '黑色', 'sku_id': xxx} # ] # }, # ... #] specs = goods.goodsspecification_set.order_by('id') # 若當前sku的規格信息不完整,則不再繼續 if len(sku_key) < len(specs): return for index, spec in enumerate(specs): # 復制當前sku的規格鍵 key = sku_key[:] # 該規格的選項 options = spec.specificationoption_set.all() for option in options: # 在規格參數sku字典中查找符合當前規格的sku key[index] = option.id option.sku_id = spec_sku_map.get(tuple(key)) spec.options = options # 渲染模板,生成靜態html文件 context = { 'categories': categories, 'goods': goods, 'specs': specs, 'sku': sku } template = loader.get_template('detail.html') html_text = template.render(context) file_path = os.path.join(settings.GENERATED_STATIC_HTML_FILES_DIR, 'goods/'+str(sku_id)+'.html') with open(file_path, 'w') as f: f.write(html_text) 

將形成商品類別部分的數據封裝成一個公共函數,放在goods/utils.py中

from collections import OrderedDict from .models import GoodsChannel def get_categories(): """ 獲取商城商品分類菜單 :return 菜單字典 """ # 商品頻道及分類菜單 # 使用有序字典保存類別的順序 # categories = { # 1: { # 組1 # 'channels': [{'id':, 'name':, 'url':},{}, {}...], # 'sub_cats': [{'id':, 'name':, 'sub_cats':[{},{}]}, {}, {}, ..] # }, # 2: { # 組2 # # } # } categories = OrderedDict() channels = GoodsChannel.objects.order_by('group_id', 'sequence') for channel in channels: group_id = channel.group_id # 當前組 if group_id not in categories: categories[group_id] = {'channels': [], 'sub_cats': []} cat1 = channel.category # 當前頻道的類別 # 追加當前頻道 categories[group_id]['channels'].append({ 'id': cat1.id, 'name': cat1.name, 'url': channel.url }) # 構建當前類別的子類別 for cat2 in cat1.goodscategory_set.all(): cat2.sub_cats = [] for cat3 in cat2.goodscategory_set.all(): cat2.sub_cats.append(cat3) categories[group_id]['sub_cats'].append(cat2) return categories


異步任務的觸發

運營人員在Admin站點保存商品信息時,應該觸發生成商品靜態頁的異步任務。

我們需要調整Admin站點保存和刪除商品信息時行為。

在Admin站點保存或刪除數據時,Django是調用的Admin站點管理器類的save_model()方法和delete_model()方法,我們只需重新實現這兩個方法,在這兩個方法中調用異步任務即可。

編輯goods/admin.py

from django.contrib import admin # Register your models here. from . import models class SKUAdmin(admin.ModelAdmin): def save_model(self, request, obj, form, change): obj.save() from celery_tasks.html.tasks import generate_static_sku_detail_html generate_static_sku_detail_html.delay(obj.id) class SKUSpecificationAdmin(admin.ModelAdmin): def save_model(self, request, obj, form, change): obj.save() from celery_tasks.html.tasks import generate_static_sku_detail_html generate_static_sku_detail_html.delay(obj.sku.id) def delete_model(self, request, obj): sku_id = obj.sku.id obj.delete() from celery_tasks.html.tasks import generate_static_sku_detail_html generate_static_sku_detail_html.delay(sku_id) class SKUImageAdmin(admin.ModelAdmin): def save_model(self, request, obj, form, change): obj.save() from celery_tasks.html.tasks import generate_static_sku_detail_html generate_static_sku_detail_html.delay(obj.sku.id) # 設置SKU默認圖片 sku = obj.sku if not sku.default_image_url: sku.default_image_url = obj.image.url sku.save() def delete_model(self, request, obj): sku_id = obj.sku.id obj.delete() from celery_tasks.html.tasks import generate_static_sku_detail_html generate_static_sku_detail_html.delay(sku_id) admin.site.register(models.GoodsCategory) admin.site.register(models.GoodsChannel) admin.site.register(models.Goods) admin.site.register(models.Brand) admin.site.register(models.GoodsSpecification) admin.site.register(models.SpecificationOption) admin.site.register(models.SKU, SKUAdmin) admin.site.register(models.SKUSpecification, SKUSpecificationAdmin) admin.site.register(models.SKUImage, SKUImageAdmin) 

腳本工具

為了開發方便,我們還可以編寫手動生成所有商品靜態頁面的腳本regenerate_detail_html.py

#!/usr/bin/env python """ 功能:手動生成所有SKU的靜態detail html文件 使用方法: ./regenerate_detail_html.py """ import sys sys.path.insert(0, '../') sys.path.insert(0, '../meiduo_mall/apps') import os if not os.getenv('DJANGO_SETTINGS_MODULE'): os.environ['DJANGO_SETTINGS_MODULE'] = 'meiduo_mall.settings.dev' import django django.setup() from django.template import loader from django.conf import settings from goods.utils import get_categories from goods.models import SKU def generate_static_sku_detail_html(sku_id): """ 生成靜態商品詳情頁面 :param sku_id: 商品sku id """ # 商品分類菜單 categories = get_categories() # 獲取當前sku的信息 sku = SKU.objects.get(id=sku_id) sku.images = sku.skuimage_set.all() # 面包屑導航信息中的頻道 goods = sku.goods goods.channel = goods.category1.goodschannel_set.all()[0] # 構建當前商品的規格鍵 sku_specs = sku.skuspecification_set.order_by('spec_id') sku_key = [] for spec in sku_specs: sku_key.append(spec.option.id) # 獲取當前商品的所有SKU skus = goods.sku_set.all() # 構建不同規格參數(選項)的sku字典 # spec_sku_map = { # (規格1參數id, 規格2參數id, 規格3參數id, ...): sku_id, # (規格1參數id, 規格2參數id, 規格3參數id, ...): sku_id, # ... # } spec_sku_map = {} for s in skus: # 獲取sku的規格參數 s_specs = s.skuspecification_set.order_by('spec_id') # 用於形成規格參數-sku字典的鍵 key = [] for spec in s_specs: key.append(spec.option.id) # 向規格參數-sku字典添加記錄 spec_sku_map[tuple(key)] = s.id # 獲取當前商品的規格信息 specs = goods.goodsspecification_set.order_by('id') # 若當前sku的規格信息不完整,則不再繼續 if len(sku_key) < len(specs): return for index, spec in enumerate(specs): # 復制當前sku的規格鍵 key = sku_key[:] # 該規格的選項 options = spec.specificationoption_set.all() for option in options: # 在規格參數sku字典中查找符合當前規格的sku key[index] = option.id option.sku_id = spec_sku_map.get(tuple(key)) spec.options = options # 渲染模板,生成靜態html文件 context = { 'categories': categories, 'goods': goods, 'specs': specs, 'sku': sku } template = loader.get_template('detail.html') html_text = template.render(context) file_path = os.path.join(settings.GENERATED_STATIC_HTML_FILES_DIR, 'goods/'+str(sku_id)+'.html') with open(file_path, 'w') as f: f.write(html_text) if __name__ == '__main__': skus = SKU.objects.all() for sku in skus: print(sku.id) generate_static_sku_detail_html(sku.id)
打賞

免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2022 CODEPRJ.COM