使用Python3.6與Django2.0.2(Django-rest-framework)以及前端vue開發的先後端分離的商城網站php
項目支持支付寶支付(暫不支持微信支付),支持手機短信驗證碼註冊, 支持第三方登陸。集成了sentry錯誤監控系統。前端
本小節內容: model設計與資源引入vue
數據庫設計,數據表結構java
mkvirtualenv -p=D:\softEnvDown\Anaconda2\envs\py36\python.exe mxshop36
http://www.django-rest-framework.org/python
已經支持django2.0了。mysql
pip install djangorestframework
pip install django
pip install markdown # Markdown support for the browsable API. pip install django-filter # Filtering support
新建django項目的時候必須指明一個裏面有django的環境。git
指定virtualenv 新建目錄github
path 中workon_home
users
startapp users
後面分析的時候咱們會來看源碼redis
點擊run,查看是否啓動成功。sql
能夠看到咱們成功的安裝運行。
database 默認sqllite
DATABASES = {
'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'vue_shop', 'USER': 'root', 'PASSWORD': 'tp158917', 'HOST':'127.0.0.1', 'OPTIONS':{'init_command': 'SET storage_engine=INNODB'}, } }
mysql的數據庫引擎有InnoDB 和 myisam
第三方登陸的庫要求使用innodb 不然會migration出錯。
使用Navicat新建數據庫
安裝mysql驅動
pip install mysqlclient
此時運行拋出異常:
super(Connection, self).__init__(*args, **kwargs2) django.db.utils.OperationalError: (1193, "Unknown system variable 'storage_engine'")
修改成:
"OPTIONS":{"init_command":"SET default_storage_engine=INNODB;"}
可能的出錯:
前往網址下載。本地安裝。
https://www.lfd.uci.edu/~gohlke/pythonlibs/
pip install pillow
上傳圖片,處理圖片。
新建文件夾
右鍵將apps & extra_apps mark成爲sources root
import sys sys.path.insert(0,BASE_DIR) sys.path.insert(0,os.path.join(BASE_DIR, 'apps')) sys.path.insert(0,os.path.join(BASE_DIR, 'extra_apps'))
經過需求分析設計數據表。看一下系統長什麼樣子
cnpm install npm run dev
首頁分析有哪些實體,須要新建哪些app來完成。
導航欄包括商品大類
更全的商品大類,大類的下面有小類。
左邊是商品類別,價格篩選搜索。排序,分頁。
商品輪播圖,促銷價格,富文本編輯。熱賣商品顯示到詳情頁。
app設計的思想,歸類。
goods 商品管理 交易管理
用戶的操做凌駕於app之上,能夠避免循環引入。用戶的收藏,用戶的操做。
通常根據經驗劃分。
startapp goods startapp trade startapp user_operation
並將這三個app拖入apps中。
此時的項目結構
自帶的user通常都是沒法知足要求的,須要咱們自行進行擴展。
users/models.py:
from datetime import datetime from django.db import models from django.contrib.auth.models import AbstractUser # Create your models here. class UserProfile(AbstractUser): """ 用戶表,新增字段以下 """ GENDER_CHOICES = ( ("male", u"男"), ("female", u"女") ) # 用戶註冊時咱們要新建user_profile 可是咱們只有手機號 name = models.CharField(max_length=30, null=True, blank=True, verbose_name="姓名") # 保存出生日期,年齡經過出生日期推算 birthday = models.DateField(null=True, blank=True, verbose_name="出生年月") gender = models.CharField(max_length=6, choices=GENDER_CHOICES, default="female", verbose_name="性別") # mobile = models.CharField(null=True, blank=True, max_length=11, verbose_name="電話") mobile = models.CharField(max_length=11, verbose_name="電話") email = models.EmailField(max_length=100, null=True, blank=True, verbose_name="郵箱") class Meta: verbose_name = "用戶" verbose_name_plural = verbose_name def __str__(self): return self.username class VerifyCode(models.Model): """ 短信驗證碼,回填驗證碼進行驗證。能夠保存在redis中 """ code = models.CharField(max_length=10, verbose_name="驗證碼") mobile = models.CharField(max_length=11, verbose_name="電話") add_time = models.DateTimeField(default=datetime.now, verbose_name="添加時間") class Meta: verbose_name = "短信驗證碼" verbose_name_plural = verbose_name def __str__(self): return self.code
注意:datetime.now 不加直接調用。
此時咱們的userprofile並無生效
setting中
# 此處重載是爲了使咱們的UserProfile生效 AUTH_USER_MODEL = "users.UserProfile"
三個類之間有其從屬關係。
注意:如下代碼中一些暫時沒有接觸到的參數在之後會介紹
在教育平臺中咱們的從屬關係經過外鍵來完成的。
這裏有三個相關的類,是否意味咱們要建三個model。model之間有從屬的外鍵關係。
可是咱們若是要去作一個無限分類,便可擴展。
分級別。目錄樹等均可以應用這個。
class GoodsCategory(models.Model): """ 商品多級分類 """ CATEGORY_TYPE = ( (1, "一級類目"), (2, "二級類目"), (3, "三級類目"), ) name = models.CharField(default="", max_length=30, verbose_name="類別名", help_text="類別名") code = models.CharField(default="", max_length=30, verbose_name="類別code", help_text="類別code") desc = models.TextField(default="", verbose_name="類別描述", help_text="類別描述") # 設置目錄樹的級別 category_type = models.IntegerField(choices=CATEGORY_TYPE, verbose_name="類目級別", help_text="類目級別") parent_category = models.ForeignKey("self", null=True, blank=True, verbose_name="父類目級別", help_text="父目錄", related_name="sub_cat") is_tab = models.BooleanField(default=False, verbose_name="是否導航", help_text="是否導航") add_time = models.DateTimeField(default=datetime.now, verbose_name="添加時間") class Meta: verbose_name = "商品類別" verbose_name_plural = verbose_name def __str__(self): return self.name
商品的某一個類下又會有多個宣傳的商標
class GoodsCategoryBrand(models.Model): """ 某一大類下的宣傳商標 """ category = models.ForeignKey(GoodsCategory, related_name='brands', null=True, blank=True, verbose_name="商品類目") name = models.CharField(default="", max_length=30, verbose_name="品牌名", help_text="品牌名") desc = models.TextField(default="", max_length=200, verbose_name="品牌描述", help_text="品牌描述") image = models.ImageField(max_length=200, upload_to="brands/") add_time = models.DateTimeField(default=datetime.now, verbose_name="添加時間") class Meta: verbose_name = "宣傳品牌" verbose_name_plural = verbose_name db_table = "goods_goodsbrand" def __str__(self): return self.name
將xadmin和ueditor拷貝進extra apps中。
settings中install app中加入
'users', 'goods', 'user_operation', 'trade', 'xadmin', 'crispy_forms', 'DjangoUeditor',
商品數據models
from DjangoUeditor.models import UEditorField class Goods(models.Model): """ 商品 """ category = models.ForeignKey(GoodsCategory, verbose_name="商品類目") goods_sn = models.CharField(max_length=50, default="", verbose_name="商品惟一貨號") name = models.CharField(max_length=100, verbose_name="商品名") click_num = models.IntegerField(default=0, verbose_name="點擊數") sold_num = models.IntegerField(default=0, verbose_name="商品銷售量") fav_num = models.IntegerField(default=0, verbose_name="收藏數") goods_num = models.IntegerField(default=0, verbose_name="庫存數") market_price = models.FloatField(default=0, verbose_name="市場價格") shop_price = models.FloatField(default=0, verbose_name="本店價格") goods_brief = models.TextField(max_length=500, verbose_name="商品簡短描述") goods_desc = UEditorField(verbose_name=u"內容", imagePath="goods/images/", width=1000, height=300, filePath="goods/files/", default='') ship_free = models.BooleanField(default=True, verbose_name="是否承擔運費") goods_front_image = models.ImageField(upload_to="goods/images/", null=True, blank=True, verbose_name="封面圖") is_new = models.BooleanField(default=False, verbose_name="是否新品") is_hot = models.BooleanField(default=False, verbose_name="是否熱銷") add_time = models.DateTimeField(default=datetime.now, verbose_name="添加時間") class Meta: verbose_name = '商品' verbose_name_plural = verbose_name def __str__(self): return self.name
可能的改進,將運費的bool值改了,或添加一個字段郵費。
商品詳情頁輪播圖models和首頁輪播的商品圖,爲適配首頁大圖
class GoodsImage(models.Model): """ 商品詳情頁輪播圖 """ goods = models.ForeignKey(Goods, verbose_name="商品", related_name="images") image = models.ImageField(upload_to="", verbose_name="圖片", null=True, blank=True) add_time = models.DateTimeField(default=datetime.now, verbose_name="添加時間") class Meta: verbose_name = '商品輪播圖' verbose_name_plural = verbose_name def __str__(self): return self.goods.name class Banner(models.Model): """ 首頁輪播的商品圖,爲適配首頁大圖 """ goods = models.ForeignKey(Goods, verbose_name="商品") image = models.ImageField(upload_to='banner', verbose_name="輪播圖片") index = models.IntegerField(default=0, verbose_name="輪播順序") add_time = models.DateTimeField(default=datetime.now, verbose_name="添加時間") class Meta: verbose_name = '首頁輪播商品' verbose_name_plural = verbose_name def __str__(self): return self.goods.name
首頁類別旁邊的商品廣告位。
搜索欄下方熱搜詞
class HotSearchWords(models.Model): """ 熱搜詞 """ keywords = models.CharField(default="", max_length=20, verbose_name="熱搜詞") index = models.IntegerField(default=0, verbose_name="排序") add_time = models.DateTimeField(default=datetime.now, verbose_name="添加時間") class Meta: verbose_name = '熱搜詞' verbose_name_plural = verbose_name def __str__(self): return self.keywords
先後端分離的項目,參數名要保持一致
訂單的基本信息存儲在表OrderInfo
訂單的訂購商品存儲在表ordergoods
一對多的關係。一個訂單會有多個商品。
class OrderInfo(models.Model): """ 訂單信息 """ ORDER_STATUS = ( ("TRADE_SUCCESS", "成功"), ("TRADE_CLOSED", "超時關閉"), ("WAIT_BUYER_PAY", "交易建立"), ("TRADE_FINISHED", "交易結束"), ("paying", "待支付"), ) PAY_TYPE = ( ("alipay", "成功"), ("wechat", "微信"), ) user = models.ForeignKey(User, verbose_name="用戶") # unique訂單號惟一 order_sn = models.CharField(max_length=30, null=True, blank=True, unique=True, verbose_name="訂單編號") # 微信支付可能會用到 nonce_str = models.CharField(max_length=50, null=True, blank=True, unique=True, verbose_name="隨機加密串") # 支付寶支付時的交易號與本系統進行關聯 trade_no = models.CharField(max_length=100, unique=True, null=True, blank=True, verbose_name=u"交易號") # 以防用戶支付到一半不支付了 pay_status = models.CharField(choices=ORDER_STATUS, default="paying", max_length=30, verbose_name="訂單狀態") # 訂單的支付類型 pay_type = models.CharField(choices=PAY_TYPE, default="alipay", max_length=10, verbose_name="支付類型") post_script = models.CharField(max_length=200, verbose_name="訂單留言") order_mount = models.FloatField(default=0.0, verbose_name="訂單金額") pay_time = models.DateTimeField(null=True, blank=True, verbose_name="支付時間") # 用戶的基本信息 address = models.CharField(max_length=100, default="", verbose_name="收貨地址") signer_name = models.CharField(max_length=20, default="", verbose_name="簽收人") singer_mobile = models.CharField(max_length=11, verbose_name="聯繫電話") add_time = models.DateTimeField(default=datetime.now, verbose_name="添加時間") class Meta: verbose_name = u"訂單基本信息" verbose_name_plural = verbose_name def __str__(self): return str(self.order_sn) class OrderGoods(models.Model): """ 訂單內的商品詳情 """ # 一個訂單對應多個商品,因此添加外鍵 order = models.ForeignKey(OrderInfo, verbose_name="訂單信息", related_name="goods") # 兩個外鍵造成一張關聯表 goods = models.ForeignKey(Goods, verbose_name="商品") goods_num = models.IntegerField(default=0, verbose_name="商品數量") add_time = models.DateTimeField(default=datetime.now, verbose_name="添加時間") class Meta: verbose_name = "訂單內商品項" verbose_name_plural = verbose_name def __str__(self): return str(self.order.order_sn)
class UserFav(models.Model): """ 用戶收藏操做 """ user = models.ForeignKey(User, verbose_name="用戶") goods = models.ForeignKey(Goods, verbose_name="商品", help_text="商品id") add_time = models.DateTimeField(default=datetime.now, verbose_name=u"添加時間") class Meta: verbose_name = '用戶收藏' verbose_name_plural = verbose_name # 未知 unique_together = ("user", "goods") def __str__(self): return self.user.username class UserAddress(models.Model): """ 用戶收貨地址 """ user = models.ForeignKey(User, verbose_name="用戶" ) province = models.CharField(max_length=100, default="", verbose_name="省份") city = models.CharField(max_length=100, default="", verbose_name="城市") district = models.CharField(max_length=100, default="", verbose_name="區域") address = models.CharField(max_length=100, default="", verbose_name="詳細地址") signer_name = models.CharField(max_length=100, default="", verbose_name="簽收人") signer_mobile = models.CharField(max_length=11, default="", verbose_name="電話") add_time = models.DateTimeField(default=datetime.now, verbose_name="添加時間") class Meta: verbose_name = "收貨地址" verbose_name_plural = verbose_name def __str__(self): return self.address class UserLeavingMessage(models.Model): """ 用戶留言 """ MESSAGE_CHOICES = ( (1, "留言"), (2, "投訴"), (3, "詢問"), (4, "售後"), (5, "求購") ) user = models.ForeignKey(User, verbose_name="用戶") message_type = models.IntegerField(default=1, choices=MESSAGE_CHOICES, verbose_name="留言類型", help_text=u"留言類型: 1(留言),2(投訴),3(詢問),4(售後),5(求購)") subject = models.CharField(max_length=100, default="", verbose_name="主題") message = models.TextField(default="", verbose_name="留言內容", help_text="留言內容") file = models.FileField(upload_to="message/images/", verbose_name="上傳的文件", help_text="上傳的文件") add_time = models.DateTimeField(default=datetime.now, verbose_name="添加時間") class Meta: verbose_name = "用戶留言" verbose_name_plural = verbose_name def __str__(self): return self.subject
tips: type是python中的關鍵詞,請使用msg_type代替。
此時運行migrations,咱們會報錯。future模塊找不到之類。
由於咱們拷貝的源碼中沒有安裝依賴包
pip install git+git://github.com/sshwsfc/xadmin.git@django2
由於使用的django2.0.2最新版
因此須要對全部的外鍵關係加上刪除時的操做,我這裏爲了方便統一
將刪除時操做,設置爲級聯刪除。
在setting中 goods
與 goods.apps.GoodsConfig
是同樣的。
makemigrations
運行makemigrations
他就會生成咱們每次數據庫變更的py腳本。
它只是用來生成這個的。真正的生成數據表必須運行migrate
這個命令纔會去執行py腳本去數據庫生成數據表。
migrate appname
就只會生成這個app表的記錄。什麼都不填會生成全部。
能夠在Navicat中查看到咱們生成的表
再也不生成auth user表,而是生成userProfile表。而admin只會傻傻的去找auth user就會報錯
會多一個文件。
django_migration這張表記錄了以前運行過的文件。查詢到運行過了就不會運行了。
若是出現問題,將goods相關表刪除,將migration中goods的記錄刪除,從新
運行 migrate
不要Navicat和migrate混用。
xadmin文件配置顯示字段等。
每一個app一個adminx文件。
import xadmin from .models import UserFav, UserLeavingMessage, UserAddress class UserFavAdmin(object): list_display = ['user', 'goods', "add_time"] class UserLeavingMessageAdmin(object): list_display = ['user', 'message_type', "message", "add_time"] class UserAddressAdmin(object): list_display = ["signer_name", "signer_mobile", "district", "address"] xadmin.site.register(UserFav, UserFavAdmin) xadmin.site.register(UserAddress, UserAddressAdmin) xadmin.site.register(UserLeavingMessage, UserLeavingMessageAdmin)
# encoding: utf-8 import xadmin from .models import Goods, GoodsCategory, GoodsImage, GoodsCategoryBrand, Banner, HotSearchWords from .models import IndexAd class GoodsAdmin(object): list_display = ["name", "click_num", "sold_num", "fav_num", "goods_num", "market_price", "shop_price", "goods_brief", "goods_desc", "is_new", "is_hot", "add_time"] search_fields = ['name', ] list_editable = ["is_hot", ] list_filter = ["name", "click_num", "sold_num", "fav_num", "goods_num", "market_price", "shop_price", "is_new", "is_hot", "add_time", "category__name"] style_fields = {"goods_desc": "ueditor"} class GoodsImagesInline(object): model = GoodsImage exclude = ["add_time"] extra = 1 style = 'tab' inlines = [GoodsImagesInline] class GoodsCategoryAdmin(object): list_display = ["name", "category_type", "parent_category", "add_time"] list_filter = ["category_type", "parent_category", "name"] search_fields = ['name', ] class GoodsBrandAdmin(object): list_display = ["category", "image", "name", "desc"] def get_context(self): context = super(GoodsBrandAdmin, self).get_context() if 'form' in context: context['form'].fields['category'].queryset = GoodsCategory.objects.filter(category_type=1) return context class BannerGoodsAdmin(object): list_display = ["goods", "image", "index"] class HotSearchAdmin(object): list_display = ["keywords", "index", "add_time"] class IndexAdAdmin(object): list_display = ["category", "goods"] xadmin.site.register(Goods, GoodsAdmin) xadmin.site.register(GoodsCategory, GoodsCategoryAdmin) xadmin.site.register(Banner, BannerGoodsAdmin) xadmin.site.register(GoodsCategoryBrand, GoodsBrandAdmin) xadmin.site.register(HotSearchWords, HotSearchAdmin) xadmin.site.register(IndexAd, IndexAdAdmin)
# encoding: utf-8 __author__ = 'mtianyan' __date__ = '2018/2/14 0014 01:16' import xadmin from .models import UserFav, UserLeavingMessage, UserAddress class UserFavAdmin(object): list_display = ['user', 'goods', "add_time"] class UserLeavingMessageAdmin(object): list_display = ['user', 'message_type', "message", "add_time"] class UserAddressAdmin(object): list_display = ["signer_name", "signer_mobile", "district", "address"] xadmin.site.register(UserFav, UserFavAdmin) xadmin.site.register(UserAddress, UserAddressAdmin) xadmin.site.register(UserLeavingMessage, UserLeavingMessageAdmin)
# encoding: utf-8 __author__ = 'mtianyan' __date__ = '2018/2/14 0014 01:17' import xadmin from xadmin import views from .models import VerifyCode class BaseSetting(object): enable_themes = True use_bootswatch = True class GlobalSettings(object): site_title = "mtianyan慕課小店" site_footer = "shop@mxonline.cn" # menu_style = "accordion" class VerifyCodeAdmin(object): list_display = ['code', 'mobile', "add_time"] xadmin.site.register(VerifyCode, VerifyCodeAdmin) xadmin.site.register(views.BaseAdminView, BaseSetting) xadmin.site.register(views.CommAdminView, GlobalSettings)
xadmin配置url
path('xadmin/', xadmin.site.urls),
createsuperuser
pip install xlwt
修改app的英文名稱
'users.apps.UsersConfig', 'goods.apps.GoodsConfig', 'trade.apps.TradeConfig', 'user_operation.apps.UserOperationConfig',
而後在apps中添加
from django.apps import AppConfig class UsersConfig(AppConfig): name = 'users' verbose_name = "用戶管理"
配置富文本:
# 富文本相關url path('ueditor/', include('DjangoUeditor.urls')),
將數據進行填充。手動錄數據太慢了。
分類不少,商品不少。
dbtools中有data和導入的腳本。
圖片複製進media
爲了讓你們進行更方便的修改保持字段一致
知識點:單獨使用django的model
兩條線兩個sub畫出三個類
訪問圖片設置
# 設置上傳文件,圖片訪問路徑 MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# 處理圖片顯示的url,使用Django自帶serve,傳入參數告訴它去哪一個路徑找,咱們有配置好的路徑MEDIAROOT re_path('media/(?P<path>.*)', serve, {"document_root": MEDIA_ROOT }),
小數據本身添加。
原文學習來自簡書 做者:天涯明月笙
原文連接:https://www.jianshu.com/p/da847259c7e3