IT策士 10余年一線大廠經(jīng)驗(yàn),專注 IT 思維、架構(gòu)、職場進(jìn)階。我會在公眾號、今日頭條持續(xù)發(fā)布最新文章,助你少走彎路。
大家好,我是IT策士。前面三節(jié)課我們把模型建好、索引加好、遷移理順了,數(shù)據(jù)庫里現(xiàn)在還是“空蕩蕩”的。今天我們就來做兩件大事:把 Django Admin 變成運(yùn)營人員的利器,同時(shí)給數(shù)據(jù)庫灌入第一批數(shù)據(jù),讓項(xiàng)目有點(diǎn)“活氣兒”。
Django Admin 是 Django 最引以為傲的“殺手锏”之一。你只需要寫很少的代碼,就能得到一個(gè)功能完整的后臺管理系統(tǒng)。電商項(xiàng)目里,管理員需要上下架商品、查看訂單、管理用戶,這些都可以在 Admin 中實(shí)現(xiàn)。
一、創(chuàng)建超級管理員賬號
要登錄 Admin,首先需要一個(gè)超級用戶。在項(xiàng)目根目錄執(zhí)行:
python manage.py createsuperuser按提示輸入用戶名、郵箱、密碼:
Username (leave blank to use 'kali'): admin
Email address: admin@example.com
Password:
Password (again):
Superuser created successfully.現(xiàn)在啟動(dòng)開發(fā)服務(wù)器:
python manage.py runserver訪問 http://127.0.0.1:8000/admin/,用剛創(chuàng)建的用戶名和密碼登錄,你會看到 Django 自帶的后臺界面,目前只顯示了默認(rèn)的“用戶”和“組”。這是因?yàn)槲覀冞€沒有把自定義模型注冊進(jìn)去。
二、注冊模型到 Admin
2.1 用戶模塊
編輯 apps/users/admin.py:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from .models import User, Address
@admin.register(User)
class UserAdmin(BaseUserAdmin):
# 在列表頁顯示的字段
list_display = ('id', 'username', 'phone', 'email', 'is_staff', 'is_active', 'date_joined')
# 可按哪些字段篩選
list_filter = ('is_staff', 'is_active')
# 搜索字段
search_fields = ('username', 'phone', 'email')
# 編輯頁分組
fieldsets = BaseUserAdmin.fieldsets + (
('額外信息', {'fields': ('phone', 'email_active')}),
)
@admin.register(Address)
class AddressAdmin(admin.ModelAdmin):
list_display = ('id', 'user', 'receiver', 'phone', 'province', 'city', 'district', 'is_default')
search_fields = ('receiver', 'phone')
list_filter = ('province', 'city')2.2 商品模塊
編輯 apps/products/admin.py:
from django.contrib import admin
from .models import Category, SPU, SKU, ProductImage
class SKUInline(admin.TabularInline):
"""在 SPU 詳情頁內(nèi)嵌 SKU 編輯"""
model = SKU
extra = 1 # 默認(rèn)顯示一個(gè)空白行
class ProductImageInline(admin.TabularInline):
"""在 SKU 詳情頁內(nèi)嵌圖片編輯"""
model = ProductImage
extra = 1
@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
list_display = ('id', 'name', 'parent', 'level', 'sort', 'is_active')
list_filter = ('is_active', 'level')
search_fields = ('name',)
@admin.register(SPU)
class SPUAdmin(admin.ModelAdmin):
list_display = ('id', 'name', 'brand', 'category', 'create_time')
search_fields = ('name', 'brand')
list_filter = ('category',)
inlines = [SKUInline] # 內(nèi)嵌 SKU 管理
@admin.register(SKU)
class SKUAdmin(admin.ModelAdmin):
list_display = ('id', 'name', 'spu', 'price', 'stock', 'sales', 'is_active')
search_fields = ('name',)
list_filter = ('is_active', 'spu__category')
inlines = [ProductImageInline] # 內(nèi)嵌圖片管理
# 可以在列表頁直接編輯上下架狀態(tài)
list_editable = ('is_active', 'price')
@admin.register(ProductImage)
class ProductImageAdmin(admin.ModelAdmin):
list_display = ('id', 'sku', 'image', 'is_main', 'sort')2.3 購物車模塊
編輯 apps/cart/admin.py:
from django.contrib import admin
from .models import CartItem
@admin.register(CartItem)
class CartItemAdmin(admin.ModelAdmin):
list_display = ('id', 'user', 'sku', 'quantity', 'is_checked', 'create_time')
list_filter = ('is_checked',)
search_fields = ('user__username', 'sku__name')2.4 訂單模塊
編輯 apps/orders/admin.py:
from django.contrib import admin
from .models import Order, OrderItem
class OrderItemInline(admin.TabularInline):
model = OrderItem
extra = 0
readonly_fields = ('sku_name', 'sku_specs', 'price', 'quantity')
@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
list_display = ('id', 'order_no', 'user', 'total_amount', 'status', 'create_time')
list_filter = ('status', 'create_time')
search_fields = ('order_no', 'user__username')
readonly_fields = ('order_no', 'address_snapshot', 'create_time', 'update_time')
inlines = [OrderItemInline]
# 可在此處添加自定義操作(如批量改為“已發(fā)貨”等)
@admin.register(OrderItem)
class OrderItemAdmin(admin.ModelAdmin):
list_display = ('id', 'order', 'sku_name', 'price', 'quantity')
search_fields = ('sku_name', 'order__order_no')2.5 支付模塊
編輯 apps/payment/admin.py:
from django.contrib import admin
from .models import Payment
@admin.register(Payment)
class PaymentAdmin(admin.ModelAdmin):
list_display = ('id', 'order', 'trade_no', 'amount', 'status', 'create_time')
list_filter = ('status',)
search_fields = ('trade_no', 'order__order_no')
readonly_fields = ('order', 'create_time', 'update_time')保存所有文件后,刷新 Admin 頁面,你會看到左側(cè)導(dǎo)航欄出現(xiàn)了我們自定義的五個(gè)模塊:用戶、地址、分類、SPU、SKU、圖片、購物車、訂單、訂單商品、支付記錄。整個(gè)后臺瞬間有模有樣了。
三、Admin 高級定制——讓后臺更好用
3.1 list_display 也能顯示關(guān)聯(lián)字段
在 SKUAdmin 中我們用 spu__category 實(shí)現(xiàn)了跨表顯示:
list_filter = ('is_active', 'spu__category')這相當(dāng)于在 SQL 中做了 JOIN,無需額外寫代碼。
3.2 使用 list_editable 實(shí)現(xiàn)列表頁快速編輯
list_editable = ('is_active', 'price')這樣在 SKU 列表頁就可以直接勾選“是否上架”或修改價(jià)格,無需點(diǎn)進(jìn)詳情頁。
3.3 自定義 Admin 操作
在 OrderAdmin 中我們可以添加批量操作,比如“批量標(biāo)記為已發(fā)貨”。在 OrderAdmin 類內(nèi)部添加:
actions = ['mark_as_shipped']
def mark_as_shipped(self, request, queryset):
updated = queryset.filter(status=1).update(status=2) # 待發(fā)貨 -> 待收貨
self.message_user(request, f'已成功將 {updated} 個(gè)訂單標(biāo)記為已發(fā)貨。')
mark_as_shipped.short_description = '批量標(biāo)記為已發(fā)貨'刷新訂單列表頁,在動(dòng)作下拉框里就能看到“批量標(biāo)記為已發(fā)貨”了。
3.4 自定義 Admin 模板標(biāo)題
編輯 django_ecommerce/urls.py(臨時(shí)測試),也可以在 settings.py 中通過 ADMIN_SITE_HEADER 等變量修改站點(diǎn)標(biāo)題。在 settings.py 末尾加上:
ADMIN_SITE_HEADER = "電商后臺管理系統(tǒng)"
ADMIN_SITE_TITLE = "電商管理"
ADMIN_INDEX_TITLE = "歡迎使用電商管理后臺"刷新 Admin,頂部的“Django 管理”就變成了“電商后臺管理系統(tǒng)”。
四、數(shù)據(jù)初始化——給空表“填飽肚子”
有了后臺,理論上我們可以逐條手動(dòng)錄入商品,但那太慢了。我們需要一種自動(dòng)化的方式來批量導(dǎo)入基礎(chǔ)數(shù)據(jù)。Django 提供了幾種方案:fixture、自定義管理命令、數(shù)據(jù)遷移。推薦使用自定義管理命令,因?yàn)樗铎`活,而且可以調(diào)用項(xiàng)目的完整代碼。
4.1 創(chuàng)建管理命令目錄結(jié)構(gòu)
在 apps/products 下新建以下目錄和文件:
apps/products/
└── management/
├── __init__.py
└── commands/
├── __init__.py
└── init_product_data.py確保每個(gè) __init__.py 都是空文件(告訴 Python 這是一個(gè)包)。
4.2 編寫初始化腳本
編輯 apps/products/management/commands/init_product_data.py:
from django.core.management.base import BaseCommand
from products.models import Category, SPU, SKU, ProductImage
from decimal import Decimal
class Command(BaseCommand):
help = '初始化商品基礎(chǔ)數(shù)據(jù)'
def handle(self, *args, **kwargs):
self.stdout.write('開始初始化數(shù)據(jù)...')
# 1. 創(chuàng)建分類
electronics = Category.objects.create(name='電子產(chǎn)品', level=1, sort=1)
phone = Category.objects.create(name='手機(jī)', parent=electronics, level=2, sort=1)
computer = Category.objects.create(name='電腦', parent=electronics, level=2, sort=2)
clothing = Category.objects.create(name='服裝', level=1, sort=2)
men = Category.objects.create(name='男裝', parent=clothing, level=2, sort=1)
women = Category.objects.create(name='女裝', parent=clothing, level=2, sort=2)
self.stdout.write(self.style.SUCCESS('分類創(chuàng)建完成'))
# 2. 創(chuàng)建 SPU
spu_iphone = SPU.objects.create(
name='iPhone 15', brand='Apple',
desc='Apple 最新款智能手機(jī)', category=phone
)
spu_macbook = SPU.objects.create(
name='MacBook Pro 16', brand='Apple',
desc='專業(yè)級筆記本電腦', category=computer
)
spu_tshirt = SPU.objects.create(
name='純棉 T 恤', brand='Uniqlo',
desc='舒適百搭的日常 T 恤', category=men
)
self.stdout.write(self.style.SUCCESS('SPU 創(chuàng)建完成'))
# 3. 創(chuàng)建 SKU
sku1 = SKU.objects.create(
spu=spu_iphone, name='iPhone 15 128GB 午夜色',
specs={'顏色': '午夜色', '存儲': '128GB'},
price=Decimal('5999.00'), cost_price=Decimal('4500.00'),
stock=100, sales=0, is_active=True
)
sku2 = SKU.objects.create(
spu=spu_iphone, name='iPhone 15 256GB 午夜色',
specs={'顏色': '午夜色', '存儲': '256GB'},
price=Decimal('6999.00'), cost_price=Decimal('5500.00'),
stock=50, sales=0, is_active=True
)
sku3 = SKU.objects.create(
spu=spu_macbook, name='MacBook Pro 16 M3 Pro 512GB',
specs={'芯片': 'M3 Pro', '存儲': '512GB'},
price=Decimal('19999.00'), cost_price=Decimal('16000.00'),
stock=30, sales=0, is_active=True
)
sku4 = SKU.objects.create(
spu=spu_tshirt, name='純棉 T 恤 白色 M',
specs={'顏色': '白色', '尺碼': 'M'},
price=Decimal('99.00'), cost_price=Decimal('50.00'),
stock=200, sales=0, is_active=True
)
sku5 = SKU.objects.create(
spu=spu_tshirt, name='純棉 T 恤 黑色 L',
specs={'顏色': '黑色', '尺碼': 'L'},
price=Decimal('99.00'), cost_price=Decimal('50.00'),
stock=150, sales=0, is_active=True
)
self.stdout.write(self.style.SUCCESS('SKU 創(chuàng)建完成'))
# 4. 給部分 SKU 創(chuàng)建主圖(先不傳實(shí)際圖片,只演示占位)
# 實(shí)際開發(fā)中可配合 File 對象或圖片 URL 導(dǎo)入
self.stdout.write(self.style.SUCCESS('初始化完成!'))4.3 執(zhí)行初始化命令
python manage.py init_product_data控制臺輸出:
開始初始化數(shù)據(jù)...
分類創(chuàng)建完成
SPU 創(chuàng)建完成
SKU 創(chuàng)建完成
初始化完成!現(xiàn)在我們回到 Admin 后臺,點(diǎn)擊“商品分類”、“SPU”、“SKU”,就能看到剛剛灌入的數(shù)據(jù)了。運(yùn)營人員可以在后臺進(jìn)一步完善圖片、修改庫存和價(jià)格。
五、補(bǔ)充:fixture 方式快速導(dǎo)入/導(dǎo)出數(shù)據(jù)
有時(shí)你需要把數(shù)據(jù)庫中的數(shù)據(jù)導(dǎo)出為 JSON 文件,備份或共享。Django 的 fixture 功能可以勝任。
導(dǎo)出數(shù)據(jù):
python manage.py dumpdata products --indent 2 > products_fixture.json導(dǎo)入數(shù)據(jù)(另一環(huán)境或清庫后恢復(fù)):
python manage.py loaddata products_fixture.jsonfixture 適用于表結(jié)構(gòu)不變的數(shù)據(jù)備份,但邏輯復(fù)雜的初始化還是推薦自定義管理命令。
六、總結(jié)與下集預(yù)告
今天我們讓 Django Admin 真正為電商項(xiàng)目服務(wù)了:
創(chuàng)建了超級管理員,成功登錄后臺;
將所有自定義模型注冊到 Admin,并通過內(nèi)聯(lián)、列表編輯、自定義操作等高級特性大幅提升了后臺的可用性;
編寫了自定義管理命令,一鍵初始化了商品分類、SPU、SKU 的基礎(chǔ)數(shù)據(jù);
了解了 fixture 的導(dǎo)出和導(dǎo)入,為后續(xù)數(shù)據(jù)備份打下基礎(chǔ)。
至此,我們的項(xiàng)目骨架、數(shù)據(jù)庫、后臺管理、初始數(shù)據(jù)已經(jīng)全部就位,接下來就是面向用戶的功能開發(fā)了。第 5 天,我將帶你做項(xiàng)目基礎(chǔ)配置的收尾工作:整合 Bootstrap 5 靜態(tài)文件、配置模板路徑、處理媒體文件上傳,打造一個(gè)漂亮統(tǒng)一的前端基礎(chǔ)。別忘了追更!
想了解更多還可以去公眾號、今日頭條搜索「IT策士」,一起升級 IT 思維 !
本文為《Django 從 0 到 1 打造完整電商平臺》系列第 4 篇,作者:IT策士,未經(jīng)授權(quán)禁止轉(zhuǎn)載。