Django項目開發全鏈路:數據庫操作、多環境配置、windows/linux項目部署一站式指南
- 一、項目初始化
- 二、創建第一個應用
- 三、數據庫與數據模型的應用
- 四、創建管理后臺用戶
- 五、數據模型與數據庫交互之添加
- 六、數據模型與數據庫交互之修改
- 七、數據模型與數據庫交互之查詢
- 八、數據模型與數據庫交互之刪除
- 九、執行原始SQL語句
- 十、視圖改寫為類視圖
- 十一、模板與靜態資源
- 十二、制作快捷命令行腳本
- 十三、多環境配置,開發、測試、正式
- 十四、windows項目部署(nssm)
- 十五、windows項目部署(IIS)
- 十六、linux項目部署(Supervisor)
- 十七、解決靜態資源無法加載(iis、nssm、supervisor、開發環境)
- 十八、日志配置
一、項目初始化
1.運行uv add django 安裝依賴,未使用uv管理工具可使用pip install django安裝,uv教程:https://blog.csdn.net/randy521520/article/details/147001879
2.運行django-admin startproject demo創建項目
3.項目新建后的目錄大致如下
manage.py: 一個命令行實用程序,可讓您與此交互 Django項目以各種方式。
mysite/: 一個目錄,它是實際Python包 項目。它的名稱是您需要用于導入的Python包名稱里面的任何東西 (例如mysite.urls)。
mysite/__init__.py: 一個空文件,它告訴Python這個目錄應該被認為是一個Python包。
mysite/settings.py: 此Django的設置/配置項目。 Django設置會告訴你所有關于如何設置 工作。
mysite/urls.py: 此Django項目的URL聲明; Django驅動的網站的 “目錄”。
mysite/asgi.py: ASGI兼容的web服務器的入口點 為你的項目服務。
mysite/wsgi.py: 兼容WSGI的web服務器的入口點 為你的項目服務。
4.修改demo下的urls.py
5.cd項目目錄demo,運行uv run python manage.py runserver 6002啟動服務,未使用uv管理工具可使用 python manage.py runserver 6002,訪問:http://127.0.0.1:6002/,將管理后臺登錄頁面,django官網地址:https://docs.djangoproject.com/en/5.2/
6.manage.py 相關命令如下
命令分類 | 命令名稱 | 功能描述 | 常用度 |
---|---|---|---|
項目與應用管理 | startproject | 創建新的 Django 項目 | ????? |
startapp | 在當前項目中創建一個新的應用 | ????? | |
開發服務器 | runserver | 啟動開發服務器,默認運行在 127.0.0.1:8000 | ????? |
數據庫操作 | makemigrations | 根據模型變更創建新的數據庫遷移文件 | ????? |
migrate | 應用數據庫遷移,使模型與數據庫同步 | ????? | |
flush | 清空數據庫中的所有數據,但不刪除表 | ???? | |
dbshell | 啟動數據庫命令行工具 | ??? | |
數據導入導出 | dumpdata | 將數據庫中的數據導出為 JSON 或 YAML 格式 | ???? |
loaddata | 從 Fixture 文件(如 JSON)中加載數據到數據庫 | ???? | |
用戶與權限管理 | createsuperuser | 創建超級用戶,用于訪問 Django 管理后臺 | ????? |
changepassword | 更改指定用戶的密碼 | ??? | |
測試與檢查 | test | 運行項目的測試套件 | ????? |
check | 檢查 Django 項目的設置和配置是否存在問題 | ????? | |
遷移管理 | showmigrations | 顯示所有應用的遷移歷史和狀態 | ???? |
sqlmigrate | 生成指定遷移文件對應的 SQL 語句 | ??? | |
squashmigrations | 將多個遷移文件壓縮成一個 | ? | |
靜態文件管理 | collectstatic | 收集所有靜態文件到 STATIC_ROOT 目錄,用于生產環境部署 | ????? |
findstatic | 查找靜態文件的絕對路徑 | ? | |
會話管理 | clearsessions | 刪除過期的會話數據 | ? |
國際化 | compilemessages | 編譯多語言翻譯文件 | ? |
緩存 | createcachetable | 創建緩存表,用于數據庫緩存 | ? |
信息查看 | showurls | 顯示項目的所有 URL 配置 | ??? |
diffsettings | 顯示當前設置與 Django 默認設置之間的差異 | ? |
二、創建第一個應用
1.cd項目目錄demo,運行uv run python manage.py startapp school新建應用,未使用uv管理工具可使用python manage.py startapp school
2.應用新建后的目錄大致如下
__init__.py - 包標識文件
admin.py - 管理員后臺配置
apps.py - 應用配置
migrations/ - 數據庫遷移目錄
models.py - 數據模型定義
tests.py - 測試文件
views.py - 視圖函數/類
'''''可選但常用的額外文件'''''
urls.py - URL路由配置
forms.py - 表單定義
serializers.py - DRF序列化器
managers.py - 自定義模型管理器
templates/ - HTML模板目錄
static/ - 靜態文件目錄(CSS, JS, 圖片)
3.修改demo中的settings.pym,在INSTALLED_APPS中加入school
4.修改school>views.py文件
5.新增school>urls.py文件
6.修改demo下的urls.py文件
7.此時訪問http://127.0.0.1:6002/school/,就可以看到歡迎光臨頁面
三、數據庫與數據模型的應用
1.修改demo下的settings.py,配置mysql數據庫,name為連接的數據庫名,需要確保該數據庫已創建
2.安裝pymysql,并修改demo下的__init__.py,作用是讓pymysql 庫偽裝成 MySQLdb 庫,以便在 Django 等框架中使用
3.修改school>models.py,創建一些學校公共的數據模型,如:班級、課程等
from django.contrib.auth.models import User
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from django.utils import timezoneclass Class(models.Model):"""班級模型字段說明:- name: 班級名稱,從預定義的年級名稱中選擇,具有唯一性- class_code: 班級代碼,對應年級編號,具有唯一性- department: 班級類型,區分理科班、文科班等不同類型- max_students: 最大學生數,限制班級容量在1-100人之間- established_date: 成立日期,記錄班級成立時間- graduation_date: 預計畢業日期,可為空的畢業時間預估- is_active: 是否活躍,標識班級當前狀態- head_teacher: 班主任,外鍵關聯到用戶模型,可為空- created_at: 創建時間,自動記錄數據創建時間- updated_at: 更新時間,自動記錄最后修改時間- description: 班級描述,可選的詳細說明文本預定義數據:- class_info: 包含1-8年級的詳細信息字典- name_choices: 基于class_info生成的班級名稱選項- class_code_choices: 基于class_info生成的班級代碼選項- department_choices: 班級類型選項列表"""class_info = {'1':{'name': '一年級','description': '一年級 - 小學起始階段,6-7歲'},'2':{'name': '二年級','description': '二年級 - 小學基礎階段,7-8歲'},'3':{'name': '三年級','description': '三年級 - 小學鞏固階段,8-9歲'},'4':{'name': '四年級','description': '四年級 - 小學提高階段,9-10歲'},'5':{'name': '五年級','description': '五年級 - 小學進階階段,10-11歲'},'6':{'name': '六年級','description': '六年級 - 小學畢業階段,11-12歲'},'7':{'name': '七年級','description': '七年級 - 初中起始階段(初一),12-13歲'},'8':{'name': '八年級','description': '八年級 - 初中中間階段(初二),13-14歲'}}# 基本信息name_choices = [(v['name'], v['description']) for k, v in class_info.items()]name = models.CharField(max_length=100, choices=name_choices,verbose_name='班級名稱',unique=True,db_comment='\n'.join([f'{name}:{description}' for name, description in name_choices]))class_code_choices = [(k, v['name']) for k, v in class_info.items()]class_code = models.CharField(max_length=20, choices=class_code_choices, verbose_name='班級代碼', unique=True,db_comment='\n'.join([f'{code}:{name}' for code, name in class_code_choices]))department_choices = [('science', '理科班'),('arts', '文科班'),('commercial', '商科班'),('general', '普通班'),('experimental', '實驗班'),('international', '國際班'),]department = models.CharField(max_length=20, choices=department_choices, verbose_name='班級類型',db_comment='\n'.join([f'{code}:{dep}' for code, dep in department_choices]))# 容量限制max_students = models.PositiveIntegerField(default=50,validators=[MinValueValidator(1), MaxValueValidator(100)],verbose_name='最大學生數',db_comment='最大學生數:1-100人')# 時間信息established_date = models.DateField(verbose_name='成立日期')graduation_date = models.DateField(verbose_name='預計畢業日期', null=True, blank=True)is_active = models.BooleanField(default=True, verbose_name='是否活躍',db_default=True)# 教師關系head_teacher = models.ForeignKey(User,on_delete=models.SET_NULL,null=True,blank=True,related_name='headed_classes',verbose_name='班主任')# 元數據created_at = models.DateTimeField(auto_now_add=True, verbose_name='創建時間')updated_at = models.DateTimeField(auto_now=True, verbose_name='更新時間')description = models.TextField(verbose_name='班級描述', blank=True)class Meta:verbose_name = '班級'verbose_name_plural = '班級管理'ordering = ['class_code', 'name']indexes = [models.Index(fields=['class_code', 'department']),models.Index(fields=['is_active']),]class Course(models.Model):"""課程模型"""course_info = {'1':{'name': '語文','description': '語文課程'},'2':{'name': '數學','description': '數學課程'},'3':{'name': '英語','description': '英語課程'},'4':{'name': '物理','description': '物理課程'},'5':{'name': '化學','description': '化學課程'},'6':{'name': '生物','description': '生物課程'},'7':{'name': '歷史','description': '歷史課程'},'8':{'name': '地理','description': '地理課程'},'9':{'name': '政治','description': '政治課程'},'10':{'name': '音樂','description': '音樂課程'},'11':{'name': '美術','description': '美術課程'},'12':{'name': '體育','description': '體育課程'},'13':{'name': '信息技術','description': '信息技術課程'},'14':{'name': '綜合','description': '綜合課程'}}# 基本信息name_choices = [(v['name'], v['description']) for k, v in course_info.items()]name = models.CharField(max_length=100, verbose_name='課程名稱', choices=name_choices,db_comment='\n'.join([f'{name}:{description}' for name, description in name_choices]))course_code_choices = [(k, v['name']) for k, v in course_info.items()]course_code = models.CharField(max_length=20, unique=True, verbose_name='課程代碼', choices=course_code_choices,db_comment='\n'.join([f'{code}:{name}' for code, name in course_code_choices]))description = models.TextField(verbose_name='課程描述', blank=True)# 學術信息course_type_choices = [('required', '必修課'),('elective', '選修課'),('practice', '實踐課'),('experiment', '實驗課'),('seminar', '研討課'),]course_type = models.CharField(max_length=20, choices=course_type_choices, verbose_name='課程類型')# 學分和學時credits = models.PositiveIntegerField(default=2,validators=[MinValueValidator(1), MaxValueValidator(10)],verbose_name='學分')total_hours = models.PositiveIntegerField(default=36,validators=[MinValueValidator(1), MaxValueValidator(200)],verbose_name='總學時')# 班級關聯target_classes = models.ManyToManyField(Class,related_name='courses',blank=True,verbose_name='開設班級',help_text='選擇這門課程面向的班級')# 時間信息start_date = models.DateField(verbose_name='開課日期', default=timezone.now)end_date = models.DateField(verbose_name='結課日期', null=True, blank=True)is_active = models.BooleanField(default=True, verbose_name='是否開課')# 課程安排CLASS_SCHEDULE_CHOICES = [('mon1', '周一第1節'),('mon2', '周一第2節'),('mon3', '周一第3節'),('mon4', '周一第4節'),('tue1', '周二第1節'),('tue2', '周二第2節'),('tue3', '周二第3節'),('tue4', '周二第4節'),('wed1', '周三第1節'),('wed2', '周三第2節'),('wed3', '周三第3節'),('wed4', '周三第4節'),('thu1', '周四第1節'),('thu2', '周四第2節'),('thu3', '周四第3節'),('thu4', '周四第4節'),('fri1', '周五第1節'),('fri2', '周五第2節'),('fri3', '周五第3節'),('fri4', '周五第4節'),]schedule = models.CharField(max_length=10,choices=CLASS_SCHEDULE_CHOICES,verbose_name='上課時間')classroom = models.CharField(max_length=50, verbose_name='教室', blank=True)# 元數據created_at = models.DateTimeField(auto_now_add=True, verbose_name='創建時間')updated_at = models.DateTimeField(auto_now=True, verbose_name='更新時間')class Meta:verbose_name = '課程'verbose_name_plural = '課程管理'ordering = ['course_code', 'name']indexes = [models.Index(fields=['course_code', 'course_type']),models.Index(fields=['is_active'])]class CourseMaterial(models.Model):"""課程資料模型"""course = models.ForeignKey(Course,on_delete=models.CASCADE,related_name='materials',verbose_name='所屬課程')title = models.CharField(max_length=200, verbose_name='資料標題')description = models.TextField(verbose_name='資料描述', blank=True)file = models.FileField(upload_to='course_materials/%Y/%m/%d/',verbose_name='資料文件')upload_date = models.DateTimeField(auto_now_add=True, verbose_name='上傳時間')is_public = models.BooleanField(default=True, verbose_name='公開訪問')class Meta:verbose_name = '課程資料'verbose_name_plural = '課程資料管理'ordering = [</