商品詳情頁

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

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

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

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中app




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.pyui

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.pyurl

#!/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)
相關文章
相關標籤/搜索