首先,這系列隨筆是我個人在學習Bobby老師的Django實戰項目中,記錄的覺得對自己來說比較重要的知識點,不是完完整整的項目步驟過程....如果有小伙伴想找完整的教程,可以看看這個(https://www.cnblogs.com/derek1184405959/p/8768059.html)
一、配置Mysql
setting.py中的設置
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'mxshop', 'USER': 'root', 'PASSWORD': 'root', 'HOST': '127.0.0.1', "OPTIONS":{"init_command":"SET storage_engine=INNODB;"} #這個是為了后面第三方登陸而指定使用的mysql數據庫的引擎,否則第三方登陸的makemigrations將會失敗。
# 注意,如果你的MYSQL版本>=5.6,改成"OPTIONS":{"init_command":"SET default_storage_engine=INNODB;"} } }
安裝驅動Mysqlclient (否則不能使用Mysql)
下載地址為“https://www.lfd.uci.edu/~gohlke/pythonlibs/”,找到你電腦對應的版本
二、項目目錄結構搭建
1、創建包apps和extra_apps
這點值得學習,通過創建兩個包可以更加方便的管理我們自定義的app和引入的第三方app。
#setting.py import os import sys # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 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'))
2、創建文件夾media(保存圖片等)和db_tools(放腳本用的)
#setting.py # 設置上傳文件的路徑 MEDIA_URL="/media/" MEDIA_ROOT=os.path.join(BASE_DIR,"media")
# urls.py from django.urls import path from django.views.static import serve
from MxShop.settings import MEDIA_ROOT urlpatterns = [ # 文件 path('media/<path:path>', serve, {'document_root': MEDIA_ROOT}), ]
三、關於Users app的設計
其實Django內部已經自動提供給我們有關user表的設計了,我們可以通過繼承它,在原基礎上進行修改,添加我們自己自定義的屬性,這樣既避免是重復造輪子,同時官方提供給我們的相對我們自己寫的安全性上更加完善。
# users app 下的models # 引入AbstractUser from django.contrib.auth.models import AbstractUser class UserProfile(AbstractUser): """ 用戶 """ 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=(("male", "男"), ("female", "女")), default="female", 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 # 這里用的username是AbstractUser里面的,如果用我們自己定義的name的話,因為我們設定該字段是可以為空的,這樣后面在用drf等陸時會出錯,因為在我們進行調式時候,只創建了超級用戶,普通用戶還沒有創建。如果用的是self.username,它會自動獲取我們超級用戶的賬號。
# setting.py AUTH_USER_MODEL = 'users.UserProfile' #在setting中把替換系統用戶,改為我們自定義的
四、商品類別的models設計
這里有個知識點,就是如何通過一個model設計出從屬關系,讓我們可以靈活的自定義一個類的級別。因為在這個項目中商品有三個等級划分,如果創建三張表來表示每一級的話,未免太不靈活,一旦增加或者刪除將很麻煩。解決辦法是用models.ForeignKey("self")指向自己。
五、如何在一個app里繼承另一個app的model下的類
例如項目中關於購物的app里,我們需要繼承用戶User,這樣才能和購物的行為綁定起來。一般的做法是直接from users.model import User導入的。這里再介紹另一種方法,就是當我們在開發第三方時,是不知道別人定好的用戶類具體放在哪里,叫什么名字,這時還用以前的做法就沒有用處了。這時我們可以用:
# get_user_model方法會去setting中找AUTH_USER_MODEL from django.contrib.auth import get_user_model User = get_user_model()
六、migrations原理
注意,因為我們自定義了UserProfile,因此在數據庫生成的時候也就是這張表,原本會自動生成的auth_user就不會出現了,這時如果使用admin是會報錯的,因為admin默認使用auth_user。
在進行第二次或者更多次數據遷移的時候,migrate是如何確定把migrations文件夾剛生成的新的py文件更新到數據庫的呢?是因為在django_migrations這張表里詳細記錄了之前migrations已運行的的py文件。因此在migrate之前會先去這張表里查詢哪些是已經運行過的了。
七、自動導入商品數據
#如何初始化數據,將圖片、文字導入到數據庫里
#知識點:獨立使用django的model
我們目前創建好了各種數據表,但數據庫中現在什么數據都還沒有,如果想要手動往數據庫中添加數據,工作量未免太大。這時我們寫個腳本導入數據。
1、db_tools下新建文件夾data,然后把前端的json文件(category_data和product_data)拷貝到里面
2、把brands和goods圖片拷貝到media目錄下
db_tools下新建文件 import_category_data.py
代碼如下:(代碼來自https://www.cnblogs.com/derek1184405959/p/8747961.html)
# db_tools/data/import_category_data.py #獨立使用django的model import sys import os #獲取當前文件的路徑(運行腳本) pwd = os.path.dirname(os.path.realpath(__file__)) #獲取項目的跟目錄 sys.path.append(pwd+"../") #要想單獨使用django的model,必須指定一個環境變量,會去settings配置找 #參照manage.py里面就知道為什么這樣設置了 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "MxShop.settings") import django django.setup() from goods.models import GoodsCategory from db_tools.data.category_data import row_data #一級類 for lev1_cat in row_data: lev1_intance = GoodsCategory() lev1_intance.code = lev1_cat["code"] lev1_intance.name = lev1_cat["name"] lev1_intance.category_type = 1 #保存到數據庫 lev1_intance.save() #二級類 for lev2_cat in lev1_cat["sub_categorys"]: lev2_intance = GoodsCategory() lev2_intance.code = lev2_cat["code"] lev2_intance.name = lev2_cat["name"] lev2_intance.category_type = 2 lev2_intance.parent_category = lev1_intance lev2_intance.save() #三級類 for lev3_cat in lev2_cat["sub_categorys"]: lev3_intance = GoodsCategory() lev3_intance.code = lev3_cat["code"] lev3_intance.name = lev3_cat["name"] lev3_intance.category_type = 3 lev3_intance.parent_category = lev2_intance lev3_intance.save()
然后運行腳本 import_category_data.py 數據就可以保存到數據庫了
同樣,導入商品。在data目錄下新建import_goods_data.py
import sys import os pwd = os.path.dirname(os.path.realpath(__file__)) sys.path.append(pwd+"../") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "MxShop.settings") import django django.setup() from goods.models import Goods, GoodsCategory, GoodsImage from db_tools.data.product_data import row_data for goods_detail in row_data: goods = Goods() goods.name = goods_detail["name"] #前端中是“¥232”,數據庫中是float類型,所以要替換掉 (這里好像是作者在爬取數據時,拿到的數據格式和我們自己在model中設定的不一樣,所以修改一下) goods.market_price = float(int(goods_detail["market_price"].replace("¥", "").replace("元", ""))) goods.shop_price = float(int(goods_detail["sale_price"].replace("¥", "").replace("元", ""))) goods.goods_brief = goods_detail["desc"] if goods_detail["desc"] is not None else "" goods.goods_desc = goods_detail["goods_desc"] if goods_detail["goods_desc"] is not None else "" # 取第一張作為封面圖 goods.goods_front_image = goods_detail["images"][0] if goods_detail["images"] else "" #取最后一個 category_name = goods_detail["categorys"][-1] # 取出當前子類對應的GoodsCategory對象,filter沒有匹配的會返回空數組,不會拋異常。 category = GoodsCategory.objects.filter(name=category_name) if category: goods.category = category[0] goods.save() for goods_image in goods_detail["images"]: goods_image_instance = GoodsImage() goods_image_instance.image = goods_image goods_image_instance.goods = goods goods_image_instance.save()
然后運行,把商品生產到數據庫中
