現(xiàn)電商網(wǎng)站:架構(gòu)設(shè)計(jì)與實(shí)戰(zhàn)解析)
1. 項(xiàng)目背景與核心問(wèn)題拆解拿到“django-flask基于python的電子商務(wù)網(wǎng)站的設(shè)計(jì)與實(shí)現(xiàn)”這個(gè)標(biāo)題我第一反應(yīng)是這不單是一個(gè)“用Python做個(gè)商城”的練手項(xiàng)目更是一個(gè)關(guān)于Web框架選型對(duì)比、系統(tǒng)架構(gòu)演進(jìn)的典型實(shí)戰(zhàn)案例。標(biāo)題里同時(shí)出現(xiàn)Django和Flask說(shuō)明設(shè)計(jì)者希望在一套業(yè)務(wù)需求下讓兩個(gè)流派的技術(shù)棧各司其職或者是在同一項(xiàng)目中對(duì)比驗(yàn)證兩種框架的工程化邊界。電商網(wǎng)站的業(yè)務(wù)核心從來(lái)不是“頁(yè)面好不好看”而是圍繞商品、庫(kù)存、訂單、支付、用戶這幾條主線的狀態(tài)流轉(zhuǎn)。從工程角度看這個(gè)項(xiàng)目最少要拆出如下問(wèn)題域用戶體系注冊(cè)、登錄、會(huì)話保持、權(quán)限區(qū)分普通用戶/管理員商品體系分類、SPU/SKU、庫(kù)存、上下架、檢索排序交易體系購(gòu)物車、訂單生成、庫(kù)存扣減、支付回調(diào)管理后臺(tái)商品管理、訂單管理、數(shù)據(jù)統(tǒng)計(jì)標(biāo)題選用了“django-flask”這種雙框架組合我在多次帶項(xiàng)目時(shí)見(jiàn)過(guò)兩類極端做法一是Django一把梭后臺(tái)管理系統(tǒng)寫(xiě)得飛快但API層總被ORM拖累二是Flask全程微服務(wù)化開(kāi)發(fā)初期很爽到訂單狀態(tài)機(jī)時(shí)開(kāi)始滿地補(bǔ)丁。這次的設(shè)計(jì)思路我認(rèn)為可以走一條更務(wù)實(shí)的路線用Django做管理后臺(tái)和核心數(shù)據(jù)模型層用Flask做面向C端的高并發(fā)API網(wǎng)關(guān)兩者共享同一套MySQL數(shù)據(jù)庫(kù)和Redis緩存層。這樣不僅貼合標(biāo)題的“雙框架”字眼也讓每個(gè)框架用到它最擅長(zhǎng)的場(chǎng)景。適合閱讀這篇內(nèi)容的人我建議是兩類剛完成Python基礎(chǔ)語(yǔ)法、想通過(guò)完整項(xiàng)目建立Web開(kāi)發(fā)全局觀的學(xué)習(xí)者以及工作中需要維護(hù)電商系統(tǒng)、想理解雙框架混合架構(gòu)取舍的開(kāi)發(fā)者。前者可以看到一個(gè)項(xiàng)目的完整生命周期后者可以直接拿走架構(gòu)設(shè)計(jì)中的核心思路和踩坑清單。2. 技術(shù)選型背后Django和Flask的邊界究竟在哪2.1 Django的優(yōu)勢(shì)區(qū)域約定俗成的高效管理面Django最被人稱道的是“自帶電池”的全家桶模式。在這個(gè)電商項(xiàng)目里Django的Admin后臺(tái)幾乎不用額外開(kāi)發(fā)就能完成運(yùn)營(yíng)人員90%的日常操作。用戶管理Django自帶的User模型和Permission體系可以快速實(shí)現(xiàn)角色劃分。結(jié)合Django Admin自帶的用戶管理界面運(yùn)營(yíng)人員可以直接凍結(jié)違規(guī)賬號(hào)、重置密碼、查看登錄日志。商品數(shù)據(jù)管理通過(guò)Django的ModelAdmin自定義list_display、search_fields、list_filter一個(gè)商品列表頁(yè)在十分鐘內(nèi)就能擁有搜索、分頁(yè)、篩選、批量上下架功能。ORM事務(wù)管理電商的核心是訂單和庫(kù)存Django的transaction.atomic()裝飾器能夠保證訂單創(chuàng)建和庫(kù)存扣減的一致性這是Flask原生不具備的易用性。我在這個(gè)項(xiàng)目中為Django分配的角色是基礎(chǔ)設(shè)施與運(yùn)營(yíng)中心。所有數(shù)據(jù)庫(kù)表結(jié)構(gòu)、模型關(guān)系、遷移腳本都在Django側(cè)定義管理后臺(tái)也直接基于Django Admin做二次開(kāi)發(fā)通過(guò)重寫(xiě)save_model和delete_model鉤子實(shí)現(xiàn)商品刪除前的庫(kù)存校驗(yàn)和訂單取消時(shí)的庫(kù)存回補(bǔ)。2.2 Flask的用武之地靈活的C端API層Flask的優(yōu)勢(shì)在于輕量、靈活、路由可控。它的上下文管理機(jī)制讓開(kāi)發(fā)者能夠精確控制每次請(qǐng)求的生命周期這在面對(duì)高并發(fā)的商品瀏覽和購(gòu)物車操作時(shí)非常有利。API響應(yīng)結(jié)構(gòu)Flask配合自定義裝飾器可以統(tǒng)一封裝返回格式為{code: 0, data: {...}, msg: success}對(duì)前端來(lái)說(shuō)契約清晰。藍(lán)圖Blueprint隔離按業(yè)務(wù)模塊拆分為user_bp、cart_bp、order_bp、product_bp每個(gè)藍(lán)圖獨(dú)立掛載到Flask應(yīng)用上模塊之間不互相污染。與Django的數(shù)據(jù)共享Flask并不直接操作Django的ORM而是通過(guò)SQLAlchemy連接同一個(gè)MySQL庫(kù)讀取已經(jīng)由Django定義好的表結(jié)構(gòu)。兩者之間通過(guò)Redis做緩存和會(huì)話層面的協(xié)同。2.3 為什么不讓一個(gè)框架干完所有事有人會(huì)問(wèn)Django的DRFDjango REST Framework也能寫(xiě)APIFlask加擴(kuò)展也能做后臺(tái)何必搞兩套我的回答是看團(tuán)隊(duì)和場(chǎng)景。開(kāi)發(fā)效率Django Admin 3天就能交付運(yùn)營(yíng)后臺(tái)Flask寫(xiě)API天然比DRF更輕序列化性能更可控?;齑詈髢蛇叺拈_(kāi)發(fā)都能在各自熟悉的地帶高速推進(jìn)。部署隔離Django服務(wù)跑在管理端口Flask服務(wù)跑在API端口兩者可以獨(dú)立水平擴(kuò)展。大促前只需要擴(kuò)Flask實(shí)例數(shù)管理后臺(tái)不受請(qǐng)求量波動(dòng)影響。代碼邊界清晰數(shù)據(jù)模型歸Django業(yè)務(wù)API歸Flask管理規(guī)則不纏繞。后續(xù)如果要做微服務(wù)拆分Flask層可以直接抽離成獨(dú)立的商品服務(wù)、訂單服務(wù)。這套架構(gòu)的注意力要放在“模型統(tǒng)一、接口靈活”這句話上。雙框架最難處理的不是寫(xiě)代碼而是約束各自團(tuán)隊(duì)不越界。提示本項(xiàng)目不做微服務(wù)拆分只做“雙進(jìn)程、共享庫(kù)”的模塊級(jí)架構(gòu)。所有Flask進(jìn)程通過(guò)環(huán)境變量感知Django數(shù)據(jù)庫(kù)配置避免硬編碼連接串導(dǎo)致的上線事故。3. 系統(tǒng)架構(gòu)與數(shù)據(jù)模型先把地基打牢3.1 整體部署拓?fù)漤?xiàng)目在服務(wù)器上的進(jìn)程布置如下Nginx負(fù)載均衡監(jiān)聽(tīng)80/443端口按路徑轉(zhuǎn)發(fā)。/api/*轉(zhuǎn)發(fā)到Flask服務(wù)/admin/*和/static/*轉(zhuǎn)發(fā)到Django服務(wù)。Django服務(wù)默認(rèn)使用uWSGI啟動(dòng)運(yùn)行在內(nèi)部端口3031。承載Admin后臺(tái)、遷移命令、定時(shí)任務(wù)。Flask服務(wù)采用Gunicorn多worker啟動(dòng)運(yùn)行在端口5000。承載用戶端所有JSON接口。MySQL 8.0主庫(kù)存儲(chǔ)全部業(yè)務(wù)數(shù)據(jù)開(kāi)啟binlog便于后續(xù)擴(kuò)容。Redis 7緩存商品熱門(mén)信息、用戶登錄態(tài)Django session key和Flask token雙重驗(yàn)證、分布式鎖。3.2 數(shù)據(jù)庫(kù)表設(shè)計(jì)細(xì)節(jié)數(shù)據(jù)表是整個(gè)項(xiàng)目里最不能返工的部分。我按電商的經(jīng)典模型設(shè)計(jì)實(shí)際開(kāi)發(fā)時(shí)表結(jié)構(gòu)略有簡(jiǎn)化但核心關(guān)系不能亂。表名主要字段說(shuō)明usersid, username, password_hash, role, statusrole區(qū)分管理員和普通用戶categoriesid, name, parent_id, level支持二級(jí)分類productsid, category_id, title, price, stock, sales, is_on_sale商品主表skusid, product_id, specs, price_diff, stock規(guī)格維度庫(kù)存和差價(jià)cartsid, user_id, sku_id, quantity, checked購(gòu)物車項(xiàng)ordersid, order_no, user_id, total_amount, status, address_id訂單主表order_itemsid, order_id, sku_id, product_title, price, quantity訂單快照paymentsid, order_id, pay_method, transaction_id, amount, status支付流水這里有幾個(gè)務(wù)實(shí)的細(xì)節(jié)訂單快照字段order_items里必須冗余商品標(biāo)題和下單價(jià)格不能通過(guò)外鍵實(shí)時(shí)去查商品表。因?yàn)樯唐穬r(jià)格隨時(shí)會(huì)變訂單要守住“成交時(shí)那一刻的價(jià)格”。這個(gè)設(shè)計(jì)在很多初學(xué)者項(xiàng)目中常被忽略。庫(kù)存扣減方案下單時(shí)先扣“可售庫(kù)存”用戶取消或超時(shí)未支付再回補(bǔ)。表里除了stock字段我額外用一個(gè)locked_stock字段記錄被鎖定未支付的量。實(shí)際可下單量是stock - locked_stock。訂單號(hào)生成不用數(shù)據(jù)庫(kù)自增ID做訂單號(hào)而是用時(shí)間戳 用戶ID后四位 隨機(jī)數(shù)拼成唯一訂單號(hào)方便財(cái)務(wù)對(duì)賬時(shí)從訂單號(hào)反查用戶和時(shí)間段。3.3 Redis緩存與數(shù)據(jù)一致性商城首頁(yè)、商品分類頁(yè)是訪問(wèn)熱點(diǎn)。我的做法是緩存Key設(shè)計(jì)product:detail:{sku_id}緩存SKU詳情category:{category_id}:products緩存分類下的商品ID列表。失效策略為主動(dòng)刪除加過(guò)期時(shí)間雙保險(xiǎn)。緩存穿透防護(hù)查詢商品時(shí)如果Redis里沒(méi)有且MySQL也沒(méi)有就把空值也緩存30秒避免惡意請(qǐng)求直接打穿數(shù)據(jù)庫(kù)。緩存與DB最終一致Django Admin后臺(tái)修改商品庫(kù)存或價(jià)格時(shí)操作完數(shù)據(jù)庫(kù)后主動(dòng)刪除相關(guān)緩存Key。由于Flask只讀緩存最多存在幾秒的短暫不一致對(duì)電商場(chǎng)景完全可以接受。4. 核心功能模塊的實(shí)操實(shí)現(xiàn)4.1 用戶注冊(cè)與登錄的雙層會(huì)話機(jī)制用戶的登錄態(tài)我是這樣設(shè)計(jì)的Flask在用戶驗(yàn)證密碼通過(guò)后生成一個(gè)token基于itsdangerous簽名的用戶ID和過(guò)期時(shí)間同時(shí)把token寫(xiě)入Redis設(shè)置7天有效期。前端每次請(qǐng)求在Authorization: Bearer {token}頭里帶上它Flask側(cè)用裝飾器解析并緩存用戶基礎(chǔ)信息。管理后臺(tái)登錄則走Django自帶認(rèn)證流程。為了讓兩套體系不沖突在users表增加一個(gè)role字段Django Admin的登錄只允許is_staffTrue的用戶進(jìn)入而Flask的注冊(cè)接口只創(chuàng)建roleuser的普通賬戶。在密碼安全上Django側(cè)直接用make_password生成哈希Flask側(cè)用標(biāo)準(zhǔn)庫(kù)的hashlib加鹽后存儲(chǔ)。兩邊的校驗(yàn)方案不同但不影響業(yè)務(wù)層因?yàn)橥粋€(gè)用戶不會(huì)同時(shí)走兩套認(rèn)證系統(tǒng)。# Flask 登錄接口核心邏輯示意 from itsdangerous import TimedJSONWebSignatureSerializer as Serializer def generate_token(user_id, expires604800): s Serializer(app.config[SECRET_KEY], expires_inexpires) token s.dumps({uid: user_id}).decode(utf-8) redis_client.setex(fuser:token:{user_id}, expires, token) return token注意Redis里存token的目的是踢人下線。如果用戶在個(gè)人中心點(diǎn)擊“退出所有設(shè)備”直接刪除該用戶的token鍵所有端都會(huì)失效。只靠JWT簽名無(wú)法做到服務(wù)端主動(dòng)失效。4.2 商品分頁(yè)與動(dòng)態(tài)篩選接口商品列表是Flask側(cè)被調(diào)用最頻繁的接口。我使用了“首屏Redis緩存商品ID列表動(dòng)態(tài)查MySQL分頁(yè)字段”的混合方案。第一次請(qǐng)求時(shí)從MySQL查出符合篩選條件的全部ID存入Redis的Set數(shù)據(jù)結(jié)構(gòu)并返回第一頁(yè)數(shù)據(jù)。后續(xù)翻頁(yè)時(shí)直接從Redis的Set里按offset截取ID再批量查MySQL補(bǔ)全商品名稱、價(jià)格、縮略圖等展示字段。排序字段按銷量、按價(jià)格、按上架時(shí)間通過(guò)不同的Sorted Set鍵分別存儲(chǔ)避免SQL反復(fù)執(zhí)行。# Flask 商品列表接口核心邏輯示意 def get_product_list(category_id, page, size, sort_key): cache_key fcategory:{category_id}:sort:{sort_key} if redis.exists(cache_key): start (page - 1) * size end start size - 1 ids redis.zrange(cache_key, start, end) else: ids, total query_ids_from_mysql(category_id, sort_key) redis.zadd(cache_key, {pid: idx for idx, pid in enumerate(ids)}) products batch_query_products_by_ids(ids) return paginate(products, page, size)這段代碼實(shí)際開(kāi)發(fā)時(shí)要注意如果分類下商品數(shù)極少緩存Key可以設(shè)短過(guò)期時(shí)間如果商品數(shù)上萬(wàn)Set的排序效率依舊很高Redis內(nèi)部是有序結(jié)構(gòu)ZRANGE的時(shí)間復(fù)雜度是O(log N M)。4.3 購(gòu)物車的合并與選中狀態(tài)計(jì)算購(gòu)物車模塊很多時(shí)候看起來(lái)簡(jiǎn)單實(shí)際上手寫(xiě)的細(xì)節(jié)極多。主要難點(diǎn)在“未登錄加購(gòu)”和“登錄后合并”之間的數(shù)據(jù)搬移。我的實(shí)現(xiàn)策略是未登錄時(shí)購(gòu)物車數(shù)據(jù)存localStorage用戶點(diǎn)擊登錄后前端把localStorage里的購(gòu)物車數(shù)組通過(guò)一個(gè)merge_cart接口提交給Flask。[ {sku_id: 1001, quantity: 2}, {sku_id: 1008, quantity: 1} ]Flask后端做三件事逐項(xiàng)檢查SKU有效性、將同SKU數(shù)量合并、剔除庫(kù)存不足的項(xiàng)并返回提示。合并完成后清空本地緩存以服務(wù)端數(shù)據(jù)為準(zhǔn)。購(gòu)物車的“全選/單選”勾選狀態(tài)我選擇在服務(wù)端存字段checked因?yàn)榻Y(jié)算頁(yè)需要精確計(jì)算勾選商品的總額。如果只存在前端用戶換設(shè)備后勾選狀態(tài)就丟了。4.4 下單時(shí)的事務(wù)邊界與鎖設(shè)計(jì)下單接口是電商項(xiàng)目里最不能出錯(cuò)的地方。我畫(huà)了一條非常明確的事務(wù)邊界訂單主表插入、訂單明細(xì)插入、庫(kù)存鎖定、購(gòu)物車清空刪項(xiàng)這四件事必須在同一個(gè)事務(wù)里完成。數(shù)據(jù)庫(kù)層面使用SELECT ... FOR UPDATE鎖定SKU行防止兩個(gè)用戶同時(shí)下單導(dǎo)致超賣(mài)。但要注意鎖的順序項(xiàng)目中必須固定按“SKU ID升序”加鎖否則兩個(gè)訂單各包含對(duì)方SKU時(shí)會(huì)產(chǎn)生死鎖。# Django 訂單創(chuàng)建事務(wù)示意 from django.db import transaction with transaction.atomic(): sku_ids [item[sku_id] for item in items] sku_objects SKU.objects.select_for_update().filter(id__insku_ids).order_by(id) for sku in sku_objects: if sku.stock - sku.locked_stock 所需數(shù)量: raise StockShortError(sku.id) order Order.objects.create(...) OrderItem.objects.bulk_create(order_items) # 更新 locked_stock事務(wù)提交后再異步發(fā)一條消息給消息隊(duì)列或直接調(diào)用Redis刪除該用戶的購(gòu)物車緩存。訂單創(chuàng)建成功后前端跳轉(zhuǎn)支付頁(yè)后端開(kāi)啟一個(gè)延遲任務(wù)15分鐘內(nèi)未支付自動(dòng)關(guān)閉。經(jīng)驗(yàn)我在項(xiàng)目里給“關(guān)閉訂單”單獨(dú)建了一張定時(shí)任務(wù)表每分鐘掃一次“已創(chuàng)建但超時(shí)未支付”的訂單。數(shù)據(jù)量少時(shí)直接輪詢數(shù)據(jù)量大了再換延遲隊(duì)列。初學(xué)者不用一上來(lái)就上Celery先把主體流程跑通。5. 雙框架協(xié)作中的通信與部署要點(diǎn)5.1 Django與Flask如何共享同一套數(shù)據(jù)這里有一個(gè)容易踩坑的認(rèn)知Django的ORM模型和Flask的SQLAlchemy模型必須手動(dòng)保持字段同步。我在項(xiàng)目中采取的方式是Django作為唯一的模型定義來(lái)源用python manage.py inspectdb倒推出Flask側(cè)需要的Model定義模板再手動(dòng)精簡(jiǎn)。每天的模型變更流程在Django中修改models.py生成并執(zhí)行遷移。在Flask項(xiàng)目中手動(dòng)同步對(duì)應(yīng)的SQLAlchemy模型字段。如果有新增表Flask側(cè)補(bǔ)充新的Blueprint路由。同步確實(shí)麻煩但換來(lái)的好處是兩邊不會(huì)因?yàn)镺RM差異而性能下降。實(shí)測(cè)中Flask側(cè)直接用SQLAlchemy Core模式table對(duì)象比用ORM映射快5%以上查詢高頻接口時(shí)盡量用Core方式。5.2 Nginx反代配置簡(jiǎn)述server { listen 80; server_name shop.example.com; location /api/ { proxy_pass http://127.0.0.1:5000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /admin/ { proxy_pass http://127.0.0.1:3031; proxy_set_header Host $host; } location /static/ { alias /data/shop/static/; } }這套配置把靜態(tài)資源請(qǐng)求徹底分流Django和Flask都不處理圖片和CSS文件。商品圖片統(tǒng)一走對(duì)象存儲(chǔ)MySQL只存圖片URL路徑避免將二進(jìn)制大字段放在業(yè)務(wù)庫(kù)里拖慢備份和查詢速度。5.3 部署后的環(huán)境變量管理生產(chǎn)環(huán)境我把敏感配置放進(jìn)了.env文件并用python-dotenv加載。Django的settings.py和Flask的config.py都從環(huán)境變量取值例如DB_NAMEshop_db DB_USERshop_user DB_PASSWORDxxx REDIS_URLredis://127.0.0.1:6379/2 SECRET_KEYrandom-generated-key有一點(diǎn)務(wù)必養(yǎng)成習(xí)慣任何環(huán)境下不要提交.env到代碼倉(cāng)庫(kù)。我見(jiàn)過(guò)太多項(xiàng)目因?yàn)?env外泄導(dǎo)致數(shù)據(jù)庫(kù)被拖庫(kù)的案例。.gitignore里必須寫(xiě)死.env。6. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄6.1 訂單重復(fù)提交導(dǎo)致庫(kù)存為負(fù)癥狀并發(fā)壓測(cè)時(shí)同一SKU的下單接口返回成功但庫(kù)存最終變成負(fù)數(shù)。原因只靠前端按鈕防重不可靠后端沒(méi)有做冪等控制。解法在orders表中為每個(gè)用戶每分鐘的訂單請(qǐng)求設(shè)置一個(gè)冪等KeyRedis中SETNX一個(gè)短期鎖。# 冪等控制偽代碼 lock_key forder_lock:{user_id}:{sku_id_group} if not redis.set(lock_key, 1, nxTrue, ex3): return jsonify({code: 429, msg: 操作太頻繁})6.2 Django Admin修改商品后Flask接口數(shù)據(jù)不更新癥狀后臺(tái)把商品價(jià)格從99改成89前端商品詳情還是99。排查思路Flask側(cè)用了Redis緩存商品詳情Django Admin的save流程沒(méi)有觸發(fā)緩存刪除。解決在Django Admin的ModelAdmin中重寫(xiě)save_model保存成功后主動(dòng)刪除對(duì)應(yīng)緩存Key。緩存的Key命名規(guī)范在這個(gè)項(xiàng)目里是product:detail:{id}和category:{category_id}:products刪除時(shí)用scan匹配前綴批量清理。6.3 Flask的SQLAlchemy連接池被耗盡癥狀壓測(cè)半小時(shí)后Flask日志出現(xiàn)TimeoutError: QueuePool limit of size 10 overflow 10 reached。原因每個(gè)請(qǐng)求獲取了數(shù)據(jù)庫(kù)連接但沒(méi)有歸還或者事務(wù)未正確提交/回滾。解決全局注冊(cè)teardown_appcontext鉤子確保每次請(qǐng)求結(jié)束都db.session.remove()。另外把連接池大小從默認(rèn)的10調(diào)到20pool_pre_pingTrue可以在連接失效時(shí)自動(dòng)重連。from flask_sqlalchemy import SQLAlchemy db SQLAlchemy() def register_db(app): app.config[SQLALCHEMY_ENGINE_OPTIONS] { pool_size: 20, pool_recycle: 3600, pool_pre_ping: True, } db.init_app(app) app.teardown_appcontext def shutdown_session(exceptionNone): db.session.remove()6.4 混合架構(gòu)下session不一致癥狀用戶從Flask API登錄后訪問(wèn)Django管理后臺(tái)仍要重新登錄。原因兩套框架的session存儲(chǔ)機(jī)制不同F(xiàn)lask默認(rèn)client-side sessionDjango默認(rèn)服務(wù)端session。處理方案不追求單點(diǎn)登錄。面向C端用戶的操作全部走Flask API管理后臺(tái)只允許roleadmin用戶登錄。兩個(gè)體系的會(huì)話在邏輯上天然隔離反而減少了安全風(fēng)險(xiǎn)。如果在后續(xù)業(yè)務(wù)中要打通可以在Redis里統(tǒng)一存session并讓兩邊共享同樣的session key生成規(guī)則。7. 項(xiàng)目后續(xù)擴(kuò)展方向這套雙框架電商項(xiàng)目完成后后續(xù)擴(kuò)展空間其實(shí)很大。我建議優(yōu)先做三件事引入Celery異步任務(wù)隊(duì)列訂單超時(shí)關(guān)閉、支付回調(diào)處理、郵件通知、庫(kù)存回補(bǔ)通知都可以切到異步隊(duì)列里去Flask進(jìn)程不再被耗時(shí)任務(wù)卡住。搜索能力升級(jí)當(dāng)前商品搜索是MySQL的LIKE匹配數(shù)據(jù)量超過(guò)十萬(wàn)條就吃力。后續(xù)可以接入Elasticsearch或者輕量級(jí)的Manticore Search把商品名、標(biāo)簽、描述統(tǒng)一建成索引檢索速度能提升一個(gè)量級(jí)。管理后臺(tái)定制化Django Admin雖然上手快但交互形態(tài)離商業(yè)后臺(tái)還有距離。可以逐步用Vue或者React做一個(gè)獨(dú)立的管理前端通過(guò)DRF或者自定義API從Django側(cè)取數(shù)。我個(gè)人在帶這個(gè)項(xiàng)目的過(guò)程中最大的感受是電商項(xiàng)目沒(méi)有一步到位的完美架構(gòu)只有基于當(dāng)前團(tuán)隊(duì)規(guī)模、業(yè)務(wù)體量不斷調(diào)整的合適方案。雙框架混合看起來(lái)增加了一些部署和溝通成本但得到的收益是每個(gè)環(huán)節(jié)都能用上最順手的工具。它既是練手項(xiàng)目里最接近真實(shí)業(yè)務(wù)的一種也最容易在后續(xù)演進(jìn)中逐步拆成微服務(wù)。如果你正卡在一個(gè)“框架全家桶到底該選誰(shuí)”的糾結(jié)里不妨用這個(gè)思路把你的電商項(xiàng)目重新盤(pán)一遍大概率能理清思路。