# [django-oscar]商品頁面新增尺寸選項 ###### django-oscar ## 1. 什麼是"option" option讓賣家可以針對商品性質新增選項,請看以下範例: > 衣服:尺寸、顏色(S/M/L、紅/黑/粉) 食物:辣度、口味(辣/不辣、草莓口味/巧克力口味) 有了這些選項,消費者就可以選擇特定類型加入購物車 賣家也能更善用頁面空間呈現商品 ## 2. 知道什麼是option後,就來新增尺寸的option吧! django-oscar預設是沒有任何option出現的(見下圖) --- ![](https://i.imgur.com/z8GrtgR.png =500x) (預設的oscar-django是沒有紅框處的) --- 為了讓商品頁出現尺寸的option 我們要先到catalogue/models.py覆寫Option類別! > 如果還沒fork要覆寫的app,記得先去fork catalogue和basket這兩個app > 這樣子你才有catalogue/models.py可以覆寫喔 > 所有customize的第一步都是先fork要改的app!(畫重點) ```python= #project/mainsite/catalogue/models.py from oscar.apps.catalogue.abstract_models import AbstractOption class Option(AbstractOption):#覆寫原本的Option # Option types TEXT = "text" INTEGER = "integer" FLOAT = "float" BOOLEAN = "boolean" DATE = "date" CHOICES = "choices" TYPE_CHOICES = ( (TEXT, _("Text")), (INTEGER, _("Integer")), (BOOLEAN, _("True / False")), (FLOAT, _("Float")), (DATE, _("Date")), (CHOICES,_("Choices")),#讓選項可以用choice的方式呈現 ) type = models.CharField(_("Type"), max_length=255, default=TEXT, choices=TYPE_CHOICES) ``` 修改好程式碼後 到 `admin/catalogue/option` 的頁面按下add按鈕 應該就可以看到下拉式選單中出現了第20行打的Choices ![](https://i.imgur.com/erwF9a4.png =400x) 我們順手新增一下「尺寸」這個option吧~ ![](https://i.imgur.com/TSVHKny.png =400x) 接著我們到 `admin/catalogue/Product` 隨便點一個已經新增好的商品 ![](https://i.imgur.com/Xw1maHS.png =500x) 往下滑,找到`Product Options`,選擇我們剛剛新增好的「尺寸」 ![](https://i.imgur.com/bNrnzel.png =380x) 接下來,因為衣服不可能永遠什麼尺寸都有,有些尺寸會比較快賣完 我們希望可以在 `Attribute` 新增尺寸這個特徵 某尺寸賣完時,我們就到 `Attribute value` 把該尺寸拿掉 而Option只要負責從 `Attribute value` 中抓值顯示就好 所以我們接下來到 `admin/catalogue/Product attribute` 新增一個名為尺寸的Attribute (Option Group的部分選multiple options是因為尺寸有很多種) ![](https://i.imgur.com/py9AeHq.png =450x) 接下來回到 `admin/catalogue/Product` 一樣先隨便點一個商品,進入編輯頁面,到 `PRODUCT ATTRIBUTE VALUES` 的地方 應該就可以選擇有哪些尺寸了! 以這張圖片為例,這個商品就是只有S、L和XL這三種尺寸 ![](https://i.imgur.com/ulGposr.png) 寫到這邊,商品頁面還沒辦法好好呈現我們的Option 我們還要再修改一下程式碼! 請回到你的程式編輯器,到basket資料夾下建一個forms.py檔案,然後把下面的程式碼放上去 (細節請見註解) ```python= # basket/forms.py from oscar.apps.basket.forms import AddToBasketForm, SimpleAddToBasketForm from django.db.models import Sum from django.forms.utils import ErrorDict from django.utils.translation import gettext_lazy as _ from oscar.core.loading import get_model from oscar.forms import widgets Line = get_model('basket', 'line') Basket = get_model('basket', 'basket') Option = get_model('catalogue', 'Option') Product = get_model('catalogue', 'product') ProductAttribute = get_model('catalogue', 'ProductAttribute') ProductAttributeValue = get_model('catalogue', 'ProductAttributeValue') def _option_text_field(option, product): return forms.CharField(label=option.name, required=option.required) def _option_integer_field(option, product): return forms.IntegerField(label=option.name, required=option.required) def _option_boolean_field(option, product): return forms.BooleanField(label=option.name, required=option.required) def _option_float_field(option, product): return forms.FloatField(label=option.name, required=option.required) def _option_date_field(option, product): return forms.DateField(label=option.name, required=option.required, widget=forms.widgets.DateInput) #把抓到的資料轉成tuple,供CHOICES顯示,你可以依照自己的資料狀況寫一個自己的trim方法 def trimAttribueValue(attr): tmp = attr.replace('尺寸: ','') size_list = tmp.split(', ') for i in range(0, len(size_list)): size_list[i] = (size_list[i],size_list[i]) # print('DIY',tuple(size_list)) size_tuple = tuple(size_list) return size_tuple #重點!就是這裡讓選項跑出來的! #記得把參數從只有option改成(option, product) def _option_choices_field(option, product): #抓「尺寸」這個Attribute attribute = ProductAttribute.objects.filter(name='尺寸') #再去抓這個「product」裡的「attribute」尺寸裡面有什麼值 product_attribute_value = ProductAttributeValue.objects.filter(attribute=attribute[0],product=product) #抓到資料後,處理一下,把內容轉換成tuple size_tuple = trimAttribueValue(str(product_attribute_value[0])) #將tuple設為choices的參數,就差不多大功告成了! return forms.ChoiceField(label=option.name, required=option.required, choices=size_tuple) class AddToBasketForm(AddToBasketForm): OPTION_FIELD_FACTORIES = { Option.TEXT: _option_text_field, Option.INTEGER: _option_integer_field, Option.BOOLEAN: _option_boolean_field, Option.FLOAT: _option_float_field, Option.DATE: _option_date_field, Option.CHOICES: _option_choices_field, } def _add_option_field(self, product, option): option_field = self.OPTION_FIELD_FACTORIES.get(option.type, Option.TEXT) (option, product)#新增product這個參數 self.fields[option.code] = option_field #這個class一定要覆寫然後pass,不然系統不會抓到你上面覆寫AddToBasketForm的內容喔! class SimpleAddToBasketForm(SimpleAddToBasketMixin, AddToBasketForm): pass ``` 噹噹!回到商品頁面,應該就可以看到尺寸的選項出現了! ![](https://i.imgur.com/QrdTTjS.png) 選個L號的加入購物車吧! ![](https://i.imgur.com/rfzqwux.png) 大功告成! ![](https://i.imgur.com/noZfbxe.png) --- 最後附上這個專案我的github https://github.com/Felice1004/onehalf-clothing-platform/ 如有任何錯誤請不吝賜教! © Felice Hsiao 2021