作:校園閑置物品換購平臺實戰(zhàn)詳解)
看到基于flask-django這種題目的時候不少同學第一反應是:這倆框架是不是得二選一?或者怕寫成用Django做了個主頁、用Flask做了個登錄頁的縫合怪。其實這類設計題目真正想考察的是你能不能理解兩個Web框架各自的能力邊界并且用一套合理的架構(gòu)讓它們協(xié)作完成一個完整業(yè)務。這個校園個人閑置物品換購平臺我當初從需求分析到部署上線完整走了一遍坑踩了不少但做完之后對Python Web開發(fā)的理解確實上了一個臺階。這篇文章我會把整套設計思路、核心數(shù)據(jù)表結(jié)構(gòu)、雙框架協(xié)作方式、關(guān)鍵代碼實現(xiàn)以及部署階段遇到的真實問題全部梳理出來。不管你是要做課程設計、畢業(yè)設計還是單純想練手兩個主流Python框架這篇都值得看完。1. 雙框架并存的核心思路:主業(yè)務收斂、輔助功能外放先直接說結(jié)論:一個項目里同時出現(xiàn)Flask和Django絕不是讓它們做重復的事而是讓每個框架去做自己最擅長的事。1.1 Django和Flask的能力邊界Django自帶ORM、Admin后臺、用戶認證體系、表單處理、CSRF防護這種全家桶特性非常適合承載業(yè)務主鏈路。對于校園閑置物品換購平臺來說用戶注冊登錄、物品發(fā)布、訂單交易、后臺審核這些核心模塊用Django來做能省掉大量重復造輪子的工作而且數(shù)據(jù)模型和數(shù)據(jù)庫遷移都通過Django ORM統(tǒng)一管理代碼維護成本低。Flask則是一個輕量級框架它不替你做任何決定但勝在靈活、啟動快、寫小服務非常順手。在這個項目里我把推薦接口、數(shù)據(jù)統(tǒng)計聚合、圖片壓縮處理這類相對獨立的輔助功能放到了Flask側(cè)。這類功能的特點是:邏輯相對獨立、調(diào)用頻率可能很高、不影響主交易流程即使某個接口掛了也不能拖垮用戶下單。1.2 雙框架協(xié)作的三種常見模式我見過不少團隊做這類雙框架項目拆法大致有三種:協(xié)作模式實現(xiàn)方式適用場景優(yōu)缺點方式A:共享數(shù)據(jù)庫獨立服務Django跑主站Flask跑API子服務兩者連同一個MySQL通過HTTP接口互相調(diào)用課程設計、畢業(yè)設計也是本文采用的方案架構(gòu)清晰、容易演示但要注意兩個框架訪問同一批表時的模型一致性問題方式B:主進程嵌入用werkzeug的DispatcherMiddleware把Flask應用作為Django的子應用掛載只想演示同時使用了兩個框架時用來交差部署簡單但兩個框架的session、中間件會互相干擾后期難維護方式C:完全微服務化各自獨立數(shù)據(jù)庫通過REST API松耦合通信分布式結(jié)課項目演示效果好但數(shù)據(jù)一致性難保證工作量也大我最終選了方式A。理由很現(xiàn)實:課程設計和畢設的評審老師最看重的是業(yè)務閉環(huán)也就是用戶能發(fā)布物品、能下單、能完成換購。共享一個MySQL能保證交易的強一致性Flask只負責讀多寫少的輔助接口就算Flask掛了Django站點的核心功能也不受影響。這其實是真實企業(yè)里主業(yè)務收斂、輔助功能外放思想的一個簡化版答辯的時候這樣講非常加分。1.3 為什么推薦先設計架構(gòu)而不是先寫代碼很多同學拿到題目第一件事就是django-admin startproject然后就開始寫models。我的建議是反過來先花半天時間把這個平臺到底有哪些角色、哪些核心流程、哪些狀態(tài)想清楚。你可以問自己三個問題:誰是系統(tǒng)用戶?學生、管理員還可能有什么?最核心的流程是什么?發(fā)布物品、發(fā)起換購、確認交換、互相評價。哪些功能寫進Django哪些拆給Flask?根據(jù)依賴關(guān)系劃分而不是按頁面劃分。想清楚這三個問題后面寫代碼就是照圖施工而不是邊寫邊改。這個項目里我最深刻的體會就是:前期架構(gòu)多花的時間后期至少能省三倍。2. 校園換購平臺的需求本質(zhì):不是簡單二手交易閑置物品換購聽起來和閑魚、轉(zhuǎn)轉(zhuǎn)差不多但落在校園場景里需求邏輯其實有明顯區(qū)別。搞清楚這些數(shù)據(jù)庫表設計才有的放矢。2.1 校園場景的三個核心差異第一,用戶身份天然可信。注冊必須綁定學校域名郵箱或?qū)W號這意味著平臺內(nèi)交易雙方的違約成本更高不需要像閑魚那樣做復雜的芝麻信用體系。第二,交易以線下自提為主。大學生活動范圍高度集中宿舍區(qū)、教學樓、食堂就是天然的交貨點。所以系統(tǒng)不需要物流模塊但要記錄交易地點偏好比如只限本校圖書館自提。第三,換購包含了物物交換和補差價。這是這個項目和普通二手交易平臺最大的區(qū)別。用戶發(fā)布物品時除了標價還可以寫明想交換什么比如用一臺Kindle換一副降噪耳機可以補差價50元。這意味著訂單表的設計不能只有買家、賣家、金額三個字段。2.2 核心角色與功能邊界我把系統(tǒng)拆成前臺、后臺、輔助服務三塊:角色核心功能所屬框架普通學生注冊登錄、瀏覽物品、發(fā)布閑置、發(fā)起換購、留言詢問、確認收貨、評價Django系統(tǒng)管理員審核物品、處理舉報、用戶封禁、數(shù)據(jù)統(tǒng)計Django Admin Flask統(tǒng)計接口輔助服務物品推薦、瀏覽量統(tǒng)計、圖片壓縮、Excel導出Flask功能邊界定了之后頁面結(jié)構(gòu)就清楚了。前臺總共沒幾個頁面:首頁(物品流)、物品詳情、發(fā)布頁、個人中心、訂單列表、站內(nèi)信。管理后臺直接用Django Admin改一改就夠用不需要額外寫。2.3 交易狀態(tài)機:整個業(yè)務最核心的部分換購流程不是簡單的下單-付款-發(fā)貨-收貨因為存在雙方交換物品的情況狀態(tài)機必須多幾條分支。我自己項目里的狀態(tài)流轉(zhuǎn)是這樣設計的:用戶A發(fā)布物品X,狀態(tài)為在售。用戶B發(fā)起購買或換購請求物品X變?yōu)榻灰字型瑫r生成一條訂單記錄。雙方約定時間地點線下驗貨。雙方都在系統(tǒng)中點擊確認交換或確認收貨訂單變?yōu)橐淹瓿?。如果任何一方在交易中超時未確認可以申請取消訂單變?yōu)橐讶∠锲稾自動回到在售。單獨把換購拎出來說:當B提出我想用物品Y換你的X時系統(tǒng)要同時鎖定X和Y兩件物品直到雙方確認完成或者取消。這個雙向鎖定邏輯容易漏寫業(yè)務代碼里一定要同時處理兩個物品的狀態(tài)。3. 數(shù)據(jù)庫設計:換購業(yè)務的核心表長什么樣選型上我用了MySQL 8.0原因無他校園網(wǎng)環(huán)境里MySQL最通用后面查資料、找問題都容易。Django側(cè)用ORM管理表結(jié)構(gòu)Flask側(cè)通過SQLAlchemy讀取同一批表。3.1 用戶表與擴展資料表Django自帶的auth_user不要直接改而是建一張profile表一對一關(guān)聯(lián)。需要存的就是學號、學校郵箱、宿舍區(qū)域、信用分、頭像路徑。class Profile(models.Model): user models.OneToOneField(User, on_deletemodels.CASCADE, related_nameprofile) student_id models.CharField(max_length20, uniqueTrue, verbose_name學號) campus_email models.EmailField(uniqueTrue, verbose_name校園郵箱) dorm_area models.CharField(max_length50, blankTrue, verbose_name宿舍區(qū)域) credit_score models.IntegerField(default100, verbose_name信用分) avatar models.ImageField(upload_toavatars/, blankTrue)為什么不直接在User上加字段?因為Django的User模型被Admin、認證、session到處引用直接改字典字段容易在后續(xù)升級或第三方庫適配時報錯。一對一的Profile幾乎是所有Django項目的標準做法。3.2 物品表:狀態(tài)和換購意向是靈魂物品表是整個平臺的流量核心字段設計直接影響后續(xù)的檢索和交易。class Item(models.Model): STATUS_CHOICES [ (on_sale, 在售), (trading, 交易中), (sold, 已售出), (off_shelf, 已下架), ] title models.CharField(max_length100) category models.ForeignKey(Category, on_deletemodels.SET_NULL, nullTrue) description models.TextField() price models.DecimalField(max_digits8, decimal_places2) want_exchange models.CharField(max_length200, blankTrue, verbose_name想換的物品) condition_level models.IntegerField(choices[(i, f{i}成新) for i in range(1, 11)]) image models.ImageField(upload_toitems/) owner models.ForeignKey(User, on_deletemodels.CASCADE, related_nameitems) status models.CharField(max_length20, choicesSTATUS_CHOICES, defaulton_sale) view_count models.IntegerField(default0) created_at models.DateTimeField(auto_now_addTrue)這里有一個值得說的細節(jié):condition_level我用了0到10的成新度而不是幾乎全新/輕微使用痕跡這樣的模糊描述。原因很簡單:成新度便于后期用SQL做排序和篩選比如只看九成新以上的物品文本字段就沒法高效查。3.3 訂單表:換購和購買共用一張表我見過很多項目把購買訂單和換購訂單分成兩張表,這是個坑。因為換購本質(zhì)上就是雙方互為買家和賣家的交易拆成兩張表后查詢我參與過的所有交易就變得非常痛苦。正確的做法是用一張order表通過判斷exchange_item字段是否為空來區(qū)分交易類型:字段類型說明id主鍵訂單號itemFK主物品buyerFK發(fā)起交易的人sellerFK物品發(fā)布者exchange_itemFK可空若為換購則指向買家提供的物品priceDecimal成交價或補差價statusCharFieldpending / confirmed / completed / cancelledcreated_at / updated_atDateTime記錄時間關(guān)鍵邏輯是:如果exchange_item不為空那么這筆訂單成交時buyer的exchange_item狀態(tài)必須變?yōu)閟old同時item狀態(tài)變?yōu)閟old。這兩個更新必須放在同一個數(shù)據(jù)庫事務里否則會出現(xiàn)A以為換成功了、B的物品還掛著賣的數(shù)據(jù)錯亂。3.4 留言、舉報、評價表這三張表結(jié)構(gòu)都比較簡單。留言表關(guān)聯(lián)物品和用戶;舉報表關(guān)聯(lián)被舉報的物品或留言;評價表關(guān)聯(lián)訂單買家和賣家各自只能評價一次用order_id reviewer_id做聯(lián)合唯一約束。這些都屬于快速迭代的表先建起來后續(xù)有需求再加字段就行。數(shù)據(jù)庫設計這塊我的實際經(jīng)驗是:不要想著一步到位建出完美表結(jié)構(gòu)先讓核心交易閉環(huán)跑通再根據(jù)實際頁面反饋補索引和字段。這個項目里我最開始沒給item.status加索引結(jié)果數(shù)據(jù)量到幾千條時首頁查詢明顯變慢后來才補上。對課程設計級別的數(shù)據(jù)量來說這一步不做也沒事但知道了對答辯有好處。4. Django主站:從注冊登錄到訂單流轉(zhuǎn)的實現(xiàn)Django側(cè)承載了平臺的全部寫操作我按用戶-物品-訂單-后臺四條線來講。4.1 校園身份驗證:注冊時攔截非校園郵箱校園平臺最大的特色是身份可信所以注冊環(huán)節(jié)要攔住校外人。實現(xiàn)方式就是在UserCreationForm的子類里重寫clean_email強制郵箱后綴為學校域名。class CampusUserCreationForm(UserCreationForm): email forms.EmailField(requiredTrue) def clean_email(self): email self.cleaned_data[email].lower() if not email.endswith(your-university.edu.cn): raise forms.ValidationError(請使用校園郵箱注冊) return email這里的your-university.edu.cn替換成你自己的學校域名即可。另一個可選的驗證是讓用戶填學號再和管理員維護的學號表比對不過課程設計階段用郵箱后綴就夠用了。4.2 物品發(fā)布的圖片處理物品發(fā)布頁用ModelForm綁定Item模型圖片上傳這塊有幾個容易踩的坑。第一個是默認的ImageField一次只支持一張圖想支持多圖就得建一個ItemImage子表;第二個是用戶上傳的原圖動輒幾兆直接存服務器既浪費空間又拖慢頁面加載。我的做法是在保存時用Pillow把圖片壓縮兩份:一份是列表頁用的縮略圖(例如400x300裁剪)一份是詳情頁用的原圖(限制最大邊1600px)。上傳邏輯寫在form.save()里重寫:def save(self, commitTrue): item super().save(commitFalse) if self.cleaned_data.get(image): img Image.open(self.cleaned_data[image]) img.thumbnail((1600, 1600)) # 壓縮后保存到 MEDIA_ROOT并重新賦值路徑 if commit: item.save() return item這段代碼的核心意圖是:不要在模板里做任何圖片縮放全部在服務端生成好物理文件。Django模板層雖然也能做縮略圖但那是在每次請求時動態(tài)處理的高并發(fā)下CPU直接被打滿。4.3 訂單狀態(tài)機的事務控制當用戶B對物品X發(fā)起換購時要同時做三件事:創(chuàng)建訂單、把X的狀態(tài)改為交易中、把B的物品Y的狀態(tài)也改為交易中。這三個寫操作必須在一個原子事務里用Django的transaction.atomic包起來。from django.db import transaction transaction.atomic def create_exchange_order(item_x, item_y, buyer, price_diff): order Order.objects.create( itemitem_x, exchange_itemitem_y, buyerbuyer, selleritem_x.owner, priceprice_diff, statuspending, ) item_x.status trading item_x.save() item_y.status trading item_y.save() return order是否要用select_for_update()加行鎖?如果只是課程設計數(shù)據(jù)量小、并發(fā)低不加也能跑。但如果你在答辯時想展示自己對并發(fā)問題的理解這是絕佳素材。select_for_update()會在數(shù)據(jù)庫層面鎖定這兩件物品的行防止兩個用戶同時發(fā)起換購導致狀態(tài)錯亂。item_x Item.objects.select_for_update().get(pkitem_x_pk) item_y Item.objects.select_for_update().get(pkitem_y_pk)這里要提醒一句:select_for_update()必須在事務內(nèi)使用也就是說調(diào)用這個查詢的函數(shù)要被transaction.atomic包裹否則鎖會在查詢后立刻釋放起不到作用。4.4 用Django Admin做管理后臺管理后臺我?guī)缀鯖]有額外寫頁面全部靠Django Admin定制。核心配置就是把Item、Order、Report注冊進去并定制列表展示字段:admin.register(Item) class ItemAdmin(admin.ModelAdmin): list_display (title, owner, price, status, created_at) list_filter (status, category) search_fields (title, owner__username) actions [force_off_shelf] admin.action(description強制下架選中物品) def force_off_shelf(self, request, queryset): queryset.update(statusoff_shelf)actions自定義操作在處理舉報時非常管用:管理員在舉報列表里看到被舉報物品勾選、下拉選擇強制下架、執(zhí)行三步搞定。不需要寫任何前端代碼。5. Flask輔助服務:推薦接口和統(tǒng)計看板怎么落地Django把主要業(yè)務包圓了那Flask在項目里到底干什么?我這邊定了兩個明確的活:推薦接口和統(tǒng)計看板。這兩塊邏輯簡單、讀多寫少、和主流程解耦非常適合用Flask起一個輕量服務。5.1 Flask推薦接口:基于瀏覽記錄的簡單協(xié)同過濾推薦這塊不用整復雜的機器學習模型課程設計階段做看過這個物品的人還在看同類物品就夠了。算法原理很簡單:根據(jù)用戶在ItemViewLog表里的瀏覽記錄找出瀏覽過當前物品的所有用戶;再查這些用戶還瀏覽過哪些同分類的物品;按出現(xiàn)次數(shù)倒序取前6個排除用戶已擁有的物品。app.route(/api/recommend/int:item_id) def recommend(item_id): item db.session.get(Item, item_id) viewers [v.user_id for v in db.session.query(ItemViewLog).filter_by(item_iditem_id)] candidates {} for uid in viewers: for vlog in db.session.query(ItemViewLog).filter_by(user_iduid).all(): if vlog.item_id ! item_id: candidates[vlog.item_id] candidates.get(vlog.item_id, 0) 1 ranked sorted(candidates.items(), keylambda x: x[1], reverseTrue)[:6] return jsonify([{item_id: k} for k, _ in ranked])這段代碼本身沒什么技術(shù)含量但它在架構(gòu)上定義了Flask負責計算、Django負責展示的協(xié)作模式。前端頁面通過fetch(/api/recommend/3)拿到推薦列表再渲染物品卡片主站代碼保持干凈。5.2 統(tǒng)計看板:給管理員看的輕量報表第二個Flask接口是統(tǒng)計看板。我需要幾組數(shù)據(jù):每日發(fā)布物品數(shù)、當前在售物品分類占比、熱門物品Top10。直接在Flask里用SQLAlchemy聚合查詢?nèi)缓蠓祷豃SON前端用Chart.js渲染圖表。app.route(/api/stats/category) def stats_category(): rows db.session.query(Item.category_id, func.count(Item.id)).group_by(Item.category_id).all() return jsonify([{category_id: cid, count: cnt} for cid, cnt in rows])這個統(tǒng)計接口如果也塞進Django里代碼量和路由復雜度都會增加。放在Flask這邊整個Django項目只需要在Admin后臺里嵌一個iframe或?qū)懸粋€fetch調(diào)用就能展示圖表。5.3 雙框架共享同一個MySQL的模型一致性問題這是整個項目里最隱蔽的坑。Django的ORM會自動給模型加字段和約束比如多對多關(guān)系會生成中間表在某些情況下還有局部索引。Flask的SQLAlchemy模型是從零手工寫的兩邊字段定義稍有出入查詢結(jié)果就可能出問題輕則查不到數(shù)據(jù)重則SQLalchemy報字段不存在。我的經(jīng)驗是:以Django的模型為準Flask側(cè)只做只讀查詢的模型定義字段精簡到只定義要用到的部分并且不允許Flask側(cè)做任何寫操作。比如Item表在Flask側(cè)只需要定義id、title、category_id、price、status、view_count這幾個字段因為推薦和統(tǒng)計只用到這些。這樣兩邊模型的字段交集很小出錯的概率就低。還有一個細節(jié):created_at字段在Flasks側(cè)定義時必須加上timezoneTrue否則查出來的時間會比實際時間慢8小時。這個問題我排查了很久最后發(fā)現(xiàn)是Django啟用了USE_TZTrueMySQL里存的是UTC時間SQLAlchemy默認按本地時間解析兩邊時區(qū)沒有對齊。5.4 Flask服務的獨立部署Flask服務最終是作為一個獨立進程跑的。開發(fā)環(huán)境直接python app.py就行部署時我用Gunicorn來啟動和Django那邊的uWSGI區(qū)分開。這樣兩個服務互不干擾Flask掛了重啟FlaskDjango掛了重啟Django。gunicorn -w 2 -b 127.0.0.1:5001 app:app日志單獨寫到flask_app.log方便排查問題。6. 開發(fā)到部署階段的真實踩坑清單這部分是全文含金量最高的地方。以下每一條我都實際遇到過不給結(jié)論直接給排查思路。6.1 Python版本和Django版本之間的兼容性先檢查服務器上的Python版本再選Django版本。Django 4.2要求Python 3.10以上如果服務器是3.8裝新版Django直接報語法錯誤。我一開始在本地Windows上用Python 3.12開發(fā)一切正常部署到Linux服務器發(fā)現(xiàn)系統(tǒng)自帶的Python是3.8最后鎖定方案是Django 4.1.7 Flask 2.3兼容性最穩(wěn)。提示:做項目前先確定團隊或?qū)嶒炇曳掌鞯腜ython版本python3 --version一看便知不要想當然裝最新版。6.2 Pillow擴展庫裝不上的問題圖片處理依賴Pillow在純凈系統(tǒng)上經(jīng)常裝失敗。報錯信息通常是RequiredDependencyException: zlib或者jpeg。原因很直白:系統(tǒng)缺底層圖片庫。解決方式:# Ubuntu/Debian sudo apt-get install libjpeg-dev zlib1g-dev pip install Pillow6.3 圖片上傳后頁面404本地開發(fā)時MEDIA_URL和MEDIA_ROOT配置正確圖片能顯示。部署到Nginx后所有圖片路徑全部404。原因是Django本身不提供靜態(tài)文件服務Nginx需要把包括/media/和/static/在內(nèi)的路徑直接代理到服務器的物理目錄。Nginx配置里加一段:location /media/ { alias /var/www/project/media/; }這個坑幾乎人人都會踩因為這屬于Nginx配置不屬于Django代碼教程里很少寫清楚。6.4 表結(jié)構(gòu)改來改去的遷移災難開發(fā)過程中我多次修改Item模型導致遷移文件堆積數(shù)據(jù)庫狀態(tài)和模型不同步的怪問題時有出現(xiàn)。后來養(yǎng)成一個習慣:每次改模型前先python manage.py makemigrations --dry-run看看即將生成的遷移操作是否符合預期再真正執(zhí)行。如果已經(jīng)亂套了怎么辦?我的經(jīng)驗是別硬修遷移文件直接重置:python manage.py migrate app_name zero python manage.py makemigrations python manage.py migrate但前提是能接受清空該app的數(shù)據(jù)。開發(fā)階段無所謂如果是接近答辯的數(shù)據(jù),就不要這么干。6.5 換購并發(fā)導致的狀態(tài)錯亂有次測試時發(fā)現(xiàn),兩個同學同時點擊換購按鈕,同一件物品生成了兩筆訂單。原因就是查詢物品狀態(tài)和創(chuàng)建訂單不在一個事務里,也沒有加行鎖。修復方案前面已經(jīng)說了:select_for_update()加transaction.atomic。這是一個非常好的答辯回答題目,面試官問到如何防止超賣時,你拿這個項目里真實修過的bug舉例,說服力遠超背書。6.6 Django時區(qū)與MySQL時區(qū)不一致前面提到Flask側(cè)查時間差8小時,其實Django側(cè)也遇到過。解決方案是:# settings.py USE_TZ True TIME_ZONE Asia/Shanghai這樣Django在讀寫MySQL時會自動把UTC時間轉(zhuǎn)換為東八區(qū)。Flask側(cè)則是手動datetime.now(timezone.utc)或者直接查詢時加上convert_tz。6.7 雙服務部署時Nginx的upstream配置兩個服務同時跑,前端要同時訪問Django的/路徑和Flask的/api/路徑,靠Nginx路由區(qū)分:upstream django_backend { server 127.0.0.1:8000; } upstream flask_backend { server 127.0.0.1:5001; } server { listen 80; server_name your-domain.com; location /api/ { proxy_pass http://flask_backend; } location / { proxy_pass http://django_backend; } }這樣一個域名同時跑兩個Python Web應用,演示的時候不用來回切換端口,交互體驗也自然。6.8 頁面模板和靜態(tài)資源的重復加載最后是一個容易被忽略的性能問題。Django的模板是每次請求都渲染一遍,如果有高頻頁面(比如首頁物品流),建議加一層緩存。最簡單的做法是Django的cache_page裝飾器緩存首頁60秒:from django.views.decorators.cache import cache_page urlpatterns [ path(, cache_page(60)(views.index), nameindex), ]加完緩存后,首頁壓力大幅下降,Flask推薦接口那邊也輕松不少。7. 答辯演示和后續(xù)擴展的建議做完項目到真正演示還有一段距離。我見過實力不錯但演示翻車的,也見過功能一般但演示節(jié)奏極好的?;趯嶋H經(jīng)驗分享幾點。7.1 演示前準備好種子數(shù)據(jù)和錄屏不要現(xiàn)場發(fā)布物品、現(xiàn)場拍圖。提前把一個品類下放滿十幾件物品,圖片用真實拍的照片而非占位圖,這樣評委打開首頁時視覺效果好很多。同理,推薦接口的演示也別用空數(shù)據(jù)庫去測,先在ItemViewLog里造好一批瀏覽記錄,否則推薦結(jié)果永遠為空。錄屏軟件開好,萬一現(xiàn)場網(wǎng)絡不穩(wěn)定或者服務沒起來,放錄屏照樣能講完。7.2 講清楚框架邊界比講功能更重要答辯時評委最常問的就是:你為什么要用Flask,Django不能做推薦接口嗎? 這時候你把第1節(jié)的架構(gòu)圖往白板上一畫,說明寫操作集中在Django、讀密集的輔助服務放Flask、共享數(shù)據(jù)庫保證一致性,評委立刻知道你理解架構(gòu)設計,而不是只會堆功能。7.3 后續(xù)可以擴展的三個方向這個項目做完后,想進一步延伸可以考慮三條線:給物品加全文搜索,用Django的SearchVector或者接入Elasticsearch,解決物品多了之后分類篩選不好用的問題;把推薦服務升級成基于用戶行為排序的算法,比如根據(jù)分類偏好加權(quán),不改變架構(gòu),只改Flask側(cè)的計算邏輯;加Redis緩存熱點數(shù)據(jù),首頁物品流和推薦結(jié)果都緩存到Redis,進一步減輕數(shù)據(jù)庫壓力。我自己做這個項目的最大體會是:技術(shù)難點不在某個框架的API上,而在如何讓兩個框架各司其職、協(xié)同不打架。把這個問題想透,你就能從跟著教程敲代碼進階到真正理解Web應用怎么搭。希望這篇能幫你少走幾個彎路。