ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Django项目搭建全攻略:从虚拟环境到Admin后台的完整实践

2026/8/15 2:07:36 拓冰建站 浏览量
Django项目搭建全攻略:从虚拟环境到Admin后台的完整实践 1. 从“Hello, World!”到“Hello, Django!”为什么你的第一个Django项目总在环境上卡壳如果你刚学Python或者已经用Flask写过几个小玩意儿现在想试试更“重量级”的Django大概率会在一开始就遇到一堆环境问题。不是pip install django报错就是创建项目后python manage.py runserver跑不起来又或者VSCode里一堆红色波浪线提示找不到模块。这太正常了我刚开始的时候也一样感觉还没开始写代码就被环境配置劝退了。其实Django搭建的核心远不止那几行命令。它更像是一次对Python项目开发环境的“标准化体检”。很多人卡壳不是因为Django复杂而是因为对Python的包管理、虚拟环境、项目结构这些基础概念理解不深或者在不同操作系统Windows/macOS/Linux上操作有差异。今天我们就抛开那些速成教程从一个有多年Python开发经验的博主视角手把手、无死角地走一遍Django项目的搭建全过程。我会把那些教程里一笔带过、但实际开发中至关重要的细节都掰开揉碎讲清楚比如为什么一定要用虚拟环境不同Python版本对Django有什么影响manage.py这个文件到底是个什么“神器”以及如何配置VSCode让它成为你开发Django的得力助手而不是绊脚石。我们的目标不仅仅是让服务器跑起来而是搭建一个干净、可维护、便于团队协作和日后部署的Django项目基石。记住好的开始是成功的一半在Web开发领域这句话尤其正确。2. 环境奠基虚拟环境、Python版本与包管理的“铁三角”在动手敲django-admin startproject之前我们必须把地基打牢。这个地基就是Python项目管理的“铁三角”Python解释器版本、虚拟环境Virtual Environment和包管理工具pip。忽略任何一点你的项目都可能在未来遇到“依赖地狱”。2.1 Python版本选择不是越新越好首先打开你的终端Windows用CMD或PowerShellmacOS/Linux用Terminal输入python --version或python3 --version。你会看到一个版本号比如Python 3.8.10或Python 3.11.4。注意很多系统默认安装了Python 2和Python 3。命令python可能指向Python 2而python3指向Python 3。Django 3.x和4.x已不再支持Python 2所以请务必确认你使用的是Python 3.6或更高版本。我强烈建议使用Python 3.8到3.11之间的一个长期支持LTS版本它们在稳定性和社区支持上都有很好的平衡。Python 3.12虽然新但一些第三方库可能还未完全适配。为什么版本重要Django本身对不同Python版本有兼容性要求。例如Django 4.2支持Python 3.8, 3.9, 3.10, 3.11。如果你用Python 3.7就无法安装Django 4.2。你可以通过 Django官方文档 查看版本对应关系。2.2 虚拟环境Virtualenv项目的“隔离病房”这是新手最容易忽略也最重要的一步。虚拟环境可以为每个Python项目创建一套独立的解释器和包安装目录避免项目间的包版本冲突。想象一下这个场景你项目A需要Django 3.2项目B需要Django 4.1。如果没有虚拟环境你全局只能安装一个版本切换项目时就会报错。虚拟环境就是为每个项目建立的“隔离病房”里面的“药品”第三方包互不干扰。创建虚拟环境的两种主流方式使用venvPython 3.3内置# 进入你的项目总目录比如叫 dev cd ~/dev # 创建一个名为 mydjango_env 的虚拟环境 python3 -m venv mydjango_env执行后会在当前目录下生成一个mydjango_env文件夹里面包含了独立的Python解释器和pip。使用virtualenv第三方工具功能更强大 首先需要安装pip install virtualenv。cd ~/dev virtualenv mydjango_env # 你也可以指定Python解释器版本 # virtualenv -p /usr/bin/python3.8 mydjango_env激活虚拟环境Windows (CMD/PowerShell):# 在CMD中 mydjango_env\Scripts\activate.bat # 在PowerShell中可能需要先设置执行策略 mydjango_env\Scripts\Activate.ps1macOS/Linux (bash/zsh):source mydjango_env/bin/activate激活成功后你的命令行提示符前面会出现虚拟环境的名字如(mydjango_env) ~/dev $。这意味着之后所有pip install操作都只影响这个环境。退出虚拟环境在任何系统下只需输入deactivate。实操心得我习惯把虚拟环境目录命名为.venv并在项目根目录下创建。这样命名清晰且以点开头在部分系统下默认隐藏不干扰项目文件视图。更重要的是务必把.venv添加到你的.gitignore文件中千万不要将虚拟环境提交到版本控制系统如Git2.3 包管理用pip安装Django并固化依赖虚拟环境激活后我们就可以安全地安装Django了。# 安装最新稳定版的Django pip install django # 安装指定版本的Django推荐避免未来版本升级导致意外 pip install django4.2.7安装完成后验证一下python -m django --version # 应该输出 4.2.7 (或你安装的版本号)关键一步生成requirements.txt这是项目依赖的“清单”。在虚拟环境激活状态下运行pip freeze requirements.txt这个命令会将当前环境下所有已安装的包及其精确版本号写入requirements.txt文件。以后在新的环境比如同事的电脑或部署服务器中只需要运行pip install -r requirements.txt就能一键复现完全相同的依赖环境。这是保证项目可重现性的生命线。3. 项目骨架生成startproject与startapp的深度解析环境准备好了现在开始创建Django项目本身。这里有两个核心命令django-admin startproject和python manage.py startapp。它们生成的每一个文件都有其特定使命。3.1 创建项目理解mysite/与manage.py在虚拟环境激活的状态下在你喜欢的位置比如~/dev执行django-admin startproject mysite这行命令会创建一个名为mysite的目录结构如下mysite/ manage.py mysite/ __init__.py settings.py urls.py asgi.py wsgi.py重要概念外层mysite/vs 内层mysite/外层mysite/是你的项目容器目录。你可以把它重命名为任何你喜欢的名字比如myproject它只是一个文件夹。内层mysite/是你的实际Python包里面包含了项目的核心配置。它的名字是你在import语句中使用的Python包名。manage.py你的瑞士军刀这个文件是Django项目的命令行工具入口。不要修改它。你几乎所有的项目管理操作都将通过它进行python manage.py runserver启动开发服务器。python manage.py startapp blog创建一个名为blog的应用。python manage.py makemigrationspython manage.py migrate管理数据库迁移。python manage.py createsuperuser创建管理员账号。3.2 创建应用AppDjango的模块化哲学Django推崇“可插拔”的应用设计。一个项目Project由多个应用App组成。每个应用是一个独立的模块负责一个特定的功能比如用户认证auth、博客blog、论坛forum等。进入外层mysite目录创建一个博客应用cd mysite python manage.py startapp blog这会生成一个blog目录blog/ __init__.py admin.py apps.py migrations/ __init__.py models.py tests.py views.py关键文件说明models.py定义数据模型数据库表结构。views.py编写视图函数或类处理业务逻辑。admin.py注册模型到Django自带的管理后台。urls.py需要手动创建。定义该应用下的URL路由。为什么要把项目拆成多个App解耦与复用一个设计良好的App比如一个用户系统可以轻松移植到其他Django项目中。代码组织清晰功能边界明确便于团队协作和维护。Django生态支持很多优秀的第三方功能都是以App的形式提供的你可以直接pip install然后添加到INSTALLED_APPS中。创建完App后必须在项目配置文件mysite/settings.py中的INSTALLED_APPS列表里注册它# mysite/settings.py INSTALLED_APPS [ django.contrib.admin, django.contrib.auth, ... # 其他默认应用 blog, # 添加你创建的应用名 ]4. 开发服务器初探与基础配置调优现在让我们让项目“活”起来。4.1 启动开发服务器并访问在项目根目录有manage.py的目录下运行python manage.py runserver你会看到类似这样的输出Watching for file changes with StatReloader Performing system checks... System check identified no issues (0 silenced). You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions. Run python manage.py migrate to apply them. July 10, 2024 - 10:00:00 Django version 4.2.7, using settings mysite.settings Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C.忽略关于未应用迁移的警告我们稍后处理。打开浏览器访问http://127.0.0.1:8000/。你应该能看到Django的“安装成功”火箭页面开发服务器的特点自动重载当你修改了Python代码并保存后服务器会自动重启大部分情况下无需手动停止再启动。仅限开发这个服务器性能和安全性都不足以用于生产环境。千万不要用它来对外提供服务。4.2 初始配置调优settings.py的几处关键修改刚创建的项目配置是通用的我们需要根据自己需求进行一些调整。打开mysite/settings.py。1. 配置数据库默认为SQLiteDjango默认使用SQLite它是一个单文件数据库非常适合开发和轻量级应用。对于初学者完全可以使用它。配置已经在DATABASES设置中写好了。 如果你想使用PostgreSQL或MySQL需要先安装对应的数据库适配器如psycopg2-binary或mysqlclient然后修改DATABASES配置。这里我们先保持默认。2. 语言和时区找到以下两行并修改让管理界面变成中文并使用中国时区。LANGUAGE_CODE zh-hans # 中文 TIME_ZONE Asia/Shanghai # 亚洲/上海时区 USE_I18N True USE_TZ True # 建议设置为True让Django处理时区感知的datetime对象3. 静态文件与媒体文件路径提前规划在文件末尾添加import os # Static files (CSS, JavaScript, Images) STATIC_URL static/ # 指定开发阶段收集静态文件的目录 STATICFILES_DIRS [os.path.join(BASE_DIR, static)] # 需要手动创建static文件夹 # Media files (用户上传的文件) MEDIA_URL media/ MEDIA_ROOT os.path.join(BASE_DIR, media) # 需要手动创建media文件夹然后在项目根目录与manage.py同级手动创建static和media文件夹。4. 应用数据库迁移回到终端按CtrlC停止服务器。然后运行以下命令来创建初始数据库表针对INSTALLED_APPS中自带的admin, auth等应用python manage.py migrate这个命令会根据migrations目录下的迁移文件在SQLite数据库文件db.sqlite3中创建对应的表。完成后再次启动服务器之前的警告信息就会消失。5. 第一个视图与URL配置理解MVT中的V和CDjango采用MVTModel-View-Template模式类似于MVC。现在我们来创建第一个页面理解View视图和URL配置Controller的一部分是如何工作的。5.1 在App中编写视图View视图是一个Python函数或类它接收一个Web请求HttpRequest对象并返回一个Web响应HttpResponse对象。打开blog/views.py写入from django.http import HttpResponse from django.shortcuts import render def index(request): 博客首页视图 # 简单地返回一段HTML文本 return HttpResponse( h1欢迎来到我的博客/h1 p这是用Django搭建的第一个页面。/p a href/about/关于我/a ) def about(request): 关于页面视图 # 使用render函数返回一个渲染后的模板稍后介绍模板 # 暂时先返回简单的HttpResponse return HttpResponse( h2关于这个博客/h2 p这是一个学习Django的实践项目。/p a href/返回首页/a )5.2 配置App级别的URL路由在blog目录下创建一个新文件urls.py这是手动创建的# blog/urls.py from django.urls import path from . import views # 从当前目录导入views模块 urlpatterns [ path(, views.index, nameindex), # 将根路径映射到index视图 path(about/, views.about, nameabout), ]这里path(about/, ...)意味着当用户访问http://127.0.0.1:8000/blog/about/时会触发about视图函数。name参数给这个URL模式起了一个别名在模板和代码中可以通过这个名字反向解析出URL非常有用。5.3 将App的URL包含到项目主路由中现在需要告诉项目当访问以/blog/开头的URL时应该去blog这个App的urls.py中查找具体的路由。修改项目根目录下的mysite/urls.py# mysite/urls.py from django.contrib import admin from django.urls import path, include # 导入include函数 urlpatterns [ path(admin/, admin.site.urls), path(blog/, include(blog.urls)), # 包含blog应用的URL配置 ]include()函数就像是一个“路由分派器”它把以blog/开头的URL请求全部转交给blog.urls模块去处理。5.4 测试你的第一个页面保存所有文件确保开发服务器正在运行如果没有运行python manage.py runserver。在浏览器中访问http://127.0.0.1:8000/blog/你应该看到“欢迎来到我的博客”的首页。http://127.0.0.1:8000/blog/about/你应该看到“关于这个博客”页面。点击页面上的链接它们应该可以互相跳转。恭喜你已经完成了Django中请求-响应循环最核心的部分URL路由 - 视图函数 - HTTP响应。6. 模板与静态文件让页面“活”起来直接返回HTML字符串在视图中非常不灵活也难以维护。Django使用模板系统Template来分离Python逻辑和HTML展示。同时我们需要引入CSS、JavaScript和图片等静态文件。6.1 创建模板目录与基础模板首先在blog应用目录下创建templates文件夹再在templates下创建blog文件夹这是Django的约定为了避免不同App间模板名冲突。结构如下blog/ templates/ blog/ base.html index.html about.html基础模板base.html 这是一个所有页面共享的骨架使用Django模板语言DTL的块block标签。!DOCTYPE html html langzh-hans head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title{% block title %}我的Django博客{% endblock %}/title {% load static %} link relstylesheet href{% static blog/css/style.css %} /head body header h1a href{% url index %}我的博客/a/h1 nav a href{% url index %}首页/a a href{% url about %}关于/a /nav /header main {% block content %} !-- 子模板的内容会插入到这里 -- {% endblock %} /main footer p© 2024 我的Django学习项目/p /footer script src{% static blog/js/main.js %}/script /body /html注意{% static path/to/file %}标签它是用来生成静态文件URL的。{% url index %}则是通过我们在urls.py中定义的name来反向生成URL这样即使URL模式改变了模板中的链接也不会失效。首页模板index.html{% extends blog/base.html %} {% block title %}首页 - 我的博客{% endblock %} {% block content %} h2最新文章/h2 ul !-- 这里未来会从数据库动态获取文章列表 -- li文章标题1 (发布日期)/li li文章标题2 (发布日期)/li /ul {% endblock %}关于页面模板about.html{% extends blog/base.html %} {% block title %}关于我们{% endblock %} {% block content %} h2关于这个网站/h2 p这是一个使用Django 4.2搭建的博客系统用于学习和实践Web开发。/p {% endblock %}6.2 修改视图以渲染模板更新blog/views.py使用render函数from django.shortcuts import render def index(request): 博客首页视图 context { page_title: 博客首页, # 未来这里可以传递从数据库查询的文章列表 } # render函数会自动在app的templates目录下寻找blog/index.html return render(request, blog/index.html, context) def about(request): 关于页面视图 return render(request, blog/about.html)6.3 配置并添加静态文件在项目根目录的static文件夹下我们之前在settings.py中配置的STATICFILES_DIRS指向的目录创建应用相关的静态子目录static/ blog/ css/ style.css js/ main.js images/一个简单的style.css示例/* static/blog/css/style.css */ body { font-family: sans-serif; line-height: 1.6; margin: 0; padding: 20px; max-width: 800px; margin: auto; background-color: #f4f4f4; } header { background: #35424a; color: white; padding: 1rem 0; text-align: center; } nav a { color: white; margin: 0 15px; text-decoration: none; } main { background: white; padding: 20px; margin-top: 20px; border-radius: 5px; }6.4 收集静态文件开发与生产在开发阶段Django的runserver会自动从STATICFILES_DIRS和各个App的static子目录中提供静态文件。这就是为什么我们访问/static/blog/css/style.css能生效。但在生产环境使用Nginx、Apache等为了提高性能通常需要运行一个命令将分散的静态文件收集到一个统一的目录python manage.py collectstatic这个命令会将所有静态文件复制到settings.py中定义的STATIC_ROOT目录中。在开发阶段我们暂时不需要运行它。现在刷新浏览器页面你应该能看到应用了CSS样式的、结构清晰的博客页面了。页面有了共同的页眉、页脚和导航栏这正是模板继承的威力。7. 模型与Admin后台用代码定义你的数据Web应用的核心是数据。Django通过模型Model来定义数据结构并通过强大的内置Admin后台来管理这些数据。7.1 定义博客文章模型打开blog/models.py我们来定义一个简单的Post文章模型from django.db import models from django.utils import timezone from django.contrib.auth.models import User class Post(models.Model): 博客文章模型 # 文章状态选项 STATUS_CHOICES ( (draft, 草稿), (published, 已发布), ) title models.CharField(max_length200, verbose_name标题) # Slug是一个短标签用于生成友好的URL slug models.SlugField(max_length250, unique_for_datepublish, verbose_nameURL标识) # 外键关联到Django内置的用户模型 author models.ForeignKey(User, on_deletemodels.CASCADE, related_nameblog_posts, verbose_name作者) body models.TextField(verbose_name正文) # 发布时间 publish models.DateTimeField(defaulttimezone.now, verbose_name发布时间) # 创建时间自动设置 created models.DateTimeField(auto_now_addTrue, verbose_name创建时间) # 更新时间自动更新 updated models.DateTimeField(auto_nowTrue, verbose_name更新时间) # 文章状态 status models.CharField(max_length10, choicesSTATUS_CHOICES, defaultdraft, verbose_name状态) class Meta: # 定义元数据 ordering (-publish,) # 默认按发布时间降序排列 verbose_name 文章 # 在Admin后台显示的单数名称 verbose_name_plural 文章 # 在Admin后台显示的复数名称 def __str__(self): # 定义对象的字符串表示在Admin后台和shell中显示 return self.title字段类型详解CharField用于短文本必须指定max_length。SlugField一种特殊的CharField通常只包含字母、数字、下划线或连字符用于URL。ForeignKey定义多对一关系。on_deletemodels.CASCADE表示当关联的User被删除时其所有文章也被删除。related_name用于从User对象反向查询其文章。TextField用于长文本不限长度。DateTimeField日期时间字段。auto_now_addTrue只在创建时自动设置为当前时间auto_nowTrue在每次保存时都更新为当前时间。choices提供一个可选值列表在表单和Admin中会显示为下拉框。7.2 创建并应用数据库迁移模型定义好后我们需要将其变化同步到数据库。这分为两步生成迁移文件Django会比较模型和当前数据库状态的差异并生成一个描述这个差异的Python脚本迁移文件。python manage.py makemigrations blog执行后会在blog/migrations/目录下生成一个类似0001_initial.py的文件。永远不要手动编辑这个文件除非你知道自己在做什么。应用迁移执行迁移文件中的指令实际修改数据库创建表、添加字段等。python manage.py migrate这个命令会应用所有未应用的迁移包括我们刚刚为blog应用生成的迁移。7.3 将模型注册到Admin后台Django的Admin后台是一个自动生成的、功能强大的数据管理界面。要让我们的Post模型出现在后台需要在blog/admin.py中注册它。from django.contrib import admin from .models import Post admin.register(Post) # 使用装饰器注册 class PostAdmin(admin.ModelAdmin): 定制Post模型在Admin后台的显示 # 列表页显示的字段 list_display (title, slug, author, publish, status) # 右侧过滤器 list_filter (status, created, publish, author) # 搜索框可搜索的字段 search_fields (title, body) # 根据slug字段自动填充title需要设置prepopulated_fields prepopulated_fields {slug: (title,)} # 层级导航日期 date_hierarchy publish # 默认排序 ordering (status, -publish)7.4 创建超级用户并登录Admin首先我们需要创建一个可以登录Admin后台的超级用户python manage.py createsuperuser按照提示输入用户名、邮箱和密码。然后确保开发服务器正在运行访问http://127.0.0.1:8000/admin/。用刚才创建的超级用户账号登录。你会看到Django默认的认证和授权模型Groups, Users以及我们刚刚注册的Posts文章模型。点击“Posts”后面的“增加”你就可以通过一个友好的表单界面来创建、编辑和删除博客文章了。所有我们在PostAdmin类中定义的定制如列表显示、过滤、搜索都会生效。这极大地简化了初期的数据管理工。8. 视图进阶与数据展示从数据库到网页现在我们有数据了接下来要做的就是将数据库中的文章动态地展示在网页上。这需要修改视图让它从数据库中查询数据并传递给模板。8.1 修改首页视图以获取文章列表更新blog/views.py中的index视图from django.shortcuts import render, get_object_or_404 from .models import Post def index(request): 博客首页视图展示已发布的文章列表 # 从数据库中获取所有状态为‘published’的文章并按发布时间倒序排列 posts Post.objects.filter(statuspublished).order_by(-publish) context { page_title: 最新文章, posts: posts, # 将文章列表传递给模板 } return render(request, blog/index.html, context)这里Post.objects是一个管理器Manager它提供了与数据库交互的接口。filter()方法用于过滤数据order_by()用于排序。-publish中的负号表示降序。8.2 创建文章详情页视图我们还需要一个视图来展示单篇文章的详情。在blog/views.py中添加def post_detail(request, year, month, day, post_slug): 文章详情页视图。 通过年、月、日和slug唯一确定一篇文章。 # 使用get_object_or_404便捷函数如果找不到对象则返回404页面 post get_object_or_404(Post, statuspublished, slugpost_slug, publish__yearyear, publish__monthmonth, publish__dayday) context { post: post, } return render(request, blog/post_detail.html, context)这个视图函数接收四个参数年、月、日、slug这些参数将从URL中捕获。8.3 更新URL配置修改blog/urls.py为详情页添加一个URL模式from django.urls import path from . import views urlpatterns [ path(, views.index, nameindex), path(about/, views.about, nameabout), # 新的详情页URL使用尖括号捕获参数 path(int:year/int:month/int:day/slug:post_slug/, views.post_detail, namepost_detail), ]URL模式中的int:year表示捕获一个整数并赋值给year参数slug:post_slug表示捕获一个符合slug格式的字符串。8.4 创建详情页模板并更新首页模板首先创建详情页模板blog/templates/blog/post_detail.html{% extends blog/base.html %} {% block title %}{{ post.title }}{% endblock %} {% block content %} article h2{{ post.title }}/h2 p classmeta 作者: {{ post.author }} | 发布时间: {{ post.publish|date:Y年m月d日 H:i }} | 最后更新: {{ post.updated|date:Y年m月d日 H:i }} /p div classpost-body {{ post.body|linebreaks }} /div /article pa href{% url index %}返回文章列表/a/p {% endblock %}这里使用了Django模板过滤器Filter|date用于格式化日期|linebreaks将文本中的换行符转换为HTML的br或p标签。然后更新首页模板blog/templates/blog/index.html使其动态显示文章列表并链接到详情页{% extends blog/base.html %} {% block title %}首页 - 我的博客{% endblock %} {% block content %} h2最新文章/h2 {% if posts %} ul classpost-list {% for post in posts %} li h3 a href{% url post_detail yearpost.publish.year monthpost.publish.month daypost.publish.day post_slugpost.slug %} {{ post.title }} /a /h3 p classmeta 作者: {{ post.author }} | 发布于: {{ post.publish|date:Y-m-d }} | 状态: {{ post.get_status_display }} /p p{{ post.body|truncatewords:30|linebreaks }}/p !-- 只显示前30个词 -- /li {% endfor %} /ul {% else %} p暂无已发布的文章。/p {% endif %} {% endblock %}注意{% url post_detail ... %}的用法我们传递了多个命名参数来反向生成详情页的URL。post.get_status_display会自动显示STATUS_CHOICES中对应的可读标签“已发布”而不是“published”。truncatewords过滤器用于截断长文本。8.5 测试动态内容登录Admin后台 (http://127.0.0.1:8000/admin/blog/post/)。创建几篇状态为“published”的文章并填写标题、slug和正文。访问博客首页 (http://127.0.0.1:8000/blog/)你应该能看到文章列表。点击任意一篇文章的标题链接应该能跳转到该文章的详情页URL格式类似于http://127.0.0.1:8000/blog/2024/07/10/my-first-post/。至此一个具备基本CRUD通过Admin后台和展示功能的微型博客系统就搭建完成了。数据从数据库Model通过视图View查询传递给模板Template渲染最终呈现给用户这就是Django MVT模式的完整流程。