1. 写在前面:为什么Django适合做全栈
我第一次接触到Django,是在一个前后端混杂的旧项目里。那时候项目代码乱得像一锅粥,前端写在后端模板里,数据库连接散落在各个文件,改一个功能要翻遍十几个文件。后来重构时选了Django,才发现原来一个Python框架能把全栈开发做得这么"整整齐齐"。你只需要一个框架、一套命令,就能把数据库、后台管理、URL路由、模板渲染、用户认证这些全栈项目必备的能力全部串起来。
这篇博文要聊的,就是Django最核心的基本配置和项目初始化。我会把从建虚拟环境到项目跑起来的过程完整走一遍,逐个拆解settings.py里的关键配置项,再聊创建app、配置数据库、部署静态文件这些必踩的环节。不管你是刚学Python的萌新,还是写了好几年脚本想转Web开发的老手,照着这篇文章操作,Django项目的基本配置都能稳稳拿下来。
2. 全栈开发的核心思维:Django到底解决什么问题
2.1 一个框架搞定前中后
Django最大的特点,是它遵循MTV架构——Model(模型)、Template(模板)、View(视图)。听着好像和MVC差不多,本质也确实是一回事,只是叫法不同。通俗点说:
- Model管数据,负责和数据库打交道。你定义好数据模型,Django自动帮你建表、查询、更新、删除。
- Template管展示,是HTML页面。Django有自己的模板语言,可以在HTML里写
{{ variable }}、{% if %}这类标签,把后端数据渲染到页面上。 - View管业务逻辑,接收用户请求、从Model取数据、丢给Template渲染,最后把结果返回给浏览器。
这套架构的最大好处是职责清晰。一个全栈项目往往涉及用户管理、内容展示、数据统计、后台维护好几块功能,如果代码全部堆在一起,后期基本没法维护。MTV把数据处理、页面展示、业务逻辑拆开,每个人(或者你自己的每个阶段)只需要关注当前在写的这一层。
2.2 自带"全家桶",省去选型纠结
做全栈开发必然会遇到这些问题:数据库用什么?ORM怎么选?用户登录怎么做?后台管理界面自己写还是用现成的?如果你用Flask这类轻量框架,这些都要自己去装库、自己去搭;但Django把这些官方内置了。
我举个实际场景:例如你需要给项目加一个管理员后台,用Django只需要在INSTALLED_APPS里确认django.contrib.admin存在,然后创建一个超级用户,登录/admin/,一个可用的后台就出来了。用户认证、Session管理、CSRF防护、消息提示、分页组件……Django全都自带。这就是为什么很多企业级Python项目选它——标准统一,团队协作成本低。
Django还自带ORM。你不需要写SQL语句,直接用Python代码操作数据库对象就行。比如你想查询所有标题包含"Django"的文章,用Django ORM写就是:
articles = Article.objects.filter(title__contains="Django")再比如删除某篇文章,只需要:
article = Article.objects.get(id=1) article.delete()这种"用Python写数据库操作"的方式对新手极其友好。你甚至可以先完全不学SQL,用Django ORM把项目做起来,之后再根据性能需求去优化。
3. 环境准备与项目初始化:从零到跑起来
3.1 虚拟环境:为什么这一步不能省
很多Django新手踩的第一个坑,就是不加虚拟环境,直接把Django装到系统Python里。当时觉得没事,等到第二个项目需要不同Django版本,或者系统升级导致依赖冲突的时候,才明白虚拟环境多重要。
虚拟环境相当于给Python项目建了一个独立的"小房间",每个房间里的第三方库互不干扰。在终端执行:
mkdir myblog cd myblog python3 -m venv venv source venv/bin/activate执行完source之后,终端前面会出现(venv)的标识,说明你已经进入了这个虚拟环境。之后再装任何Python包,都被装到当前项目的这个环境里,不会污染全局。
提示:Windows系统激活虚拟环境的方式略有不同,是
venv\Scripts\activate。macOS和Linux用source venv/bin/activate。如果你用的是VS Code,选中解释器时也可以直接选项目里的venv目录,等效于激活虚拟环境。
激活后安装Django:
pip install django装完确认版本:
python -m django --version这里我习惯指定版本安装,例如生产环境更稳妥的做法是:
pip install django==5.0.6为什么要写死版本?因为Django每个大版本之间确实有差异,比如路由写法、某些配置默认值会变。如果你用pip install django装的是最新版,换个环境或者照着教程操作时版本不同,可能遇到莫名其妙的报错。指定版本号,至少保证你的开发环境和教程、和同事保持一致。
3.2 创建项目:django-admin startproject背后发生了什么
项目名以myblog为例。虚拟环境激活后,在项目根目录执行:
django-admin startproject config .注意最后的.,很多人漏掉它。加上点的意思是"把项目生成在当前目录",不加的话,Django会新建一个config目录再把文件放进去,导致目录层级多了一层,后面跑命令容易搞混。
执行完,当前目录结构大概长这样:
myblog/ ├── manage.py ├── config/ │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ ├── asgi.py │ └── wsgi.pymanage.py是项目管理的入口,之后执行迁移、创建app、启动服务器都是通过它。config/settings.py是整个项目的核心配置文件,我们第三部分会逐个拆。urls.py负责URL路由分发,wsgi.py和asgi.py是部署时给服务器用的入口文件,本地开发阶段不需要动。
3.3 启动开发服务器:第一个里程碑
在项目根目录执行:
python manage.py runserver默认端口是8000,浏览器访问http://127.0.0.1:8000,看到Django的火箭起飞页面,项目就算跑起来了。
这个火箭页面严格来说不算你的网站,它只是Django确认"环境没问题"的表示。想换端口可以指定:
python manage.py runserver 8080我经常用这个方式同时跑两个项目,一个占8000,一个占8080,互不干扰。
注意:生产部署时绝对不能使用
runserver,它是开发用服务器,性能和安全性都不够。部署时我们用的是Gunicorn或uWSGI这类WSGI服务器。本地开发阶段用runserver完全没问题,它甚至支持代码修改后自动重启,省去手动重启的麻烦。
4. 核心配置逐个拆解:settings.py到底在配什么
settings.py是Django项目配置的大本营。新手打开这个文件,看到一大堆大写变量容易懵。我按优先级逐个说。
4.1 SECRET_KEY与DEBUG:两个必须搞懂的配置
SECRET_KEY是Django用来自签名Session、CSRF令牌、密码哈希的密钥,极其重要。默认生成的key已经能跑项目,但如果要部署上线,千万别用默认值,必须在环境变量里覆盖它,并且绝对不要提交到Git仓库。
DEBUG默认是True。它的作用是:开发阶段出错时,页面会显示完整的错误堆栈和调试信息,方便定位问题。但生产环境必须设为False,否则一旦代码出错,攻击者能看到你的源码路径、环境变量、数据库配置这些敏感信息。我刚做项目时就吃过这个亏,上线忘了关DEBUG,页面直接把我服务器上的绝对路径暴露了,还好第二天就发现改掉了。
4.2 INSTALLED_APPS与MIDDLEWARE:项目的"插件清单"
INSTALLED_APPS是Django用来记录"这个项目启用了哪些功能模块"的列表。你可以把它理解成一部手机的已安装应用列表:
INSTALLED_APPS = [ "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", ]这里面每一项都有明确用途:
admin:后台管理界面,自动生成、自动注册模型。auth:用户认证系统,处理登录、权限、Session。contenttypes:Django的"内容类型"框架,很多高级功能依赖它。sessions:Session机制,用于在服务器端保存用户状态。messages:一次性消息提示,常用于表单提交后显示"保存成功"。staticfiles:静态文件管理,最终负责收集CSS、JS等静态资源。
我们自己创建的app,比如blog,也要加进这个列表。
MIDDLEWARE则是请求/响应处理的"流水线"。每个请求进来都会依次经过这些中间件,比如SessionMiddleware管理Session,CsrfViewMiddleware提供CSRF防护,AuthenticationMiddleware把当前登录用户挂到request.user上。除非你明确知道自己在干什么,否则不要随意删改中间件。安全防护全靠它们兜底。
4.3 DATABASES:接入你想用的数据库
Django默认配置的是sqlite3:
DATABASES = { "default": { "ENGINE": "django.db.backends.sqlite3", "NAME": "BASE_DIR / "db.sqlite3", } }很多人一开始会纠结要不要立刻换MySQL或PostgreSQL。我的建议是:本地开发初期直接用SQLite完全没问题,它不需要额外安装,所有数据存在一个文件里,特别适合学习和快速原型验证。等到项目要部署了,再改成PostgreSQL或MySQL。
切换数据库很简单,比如换成MySQL:
DATABASES = { "default": { "ENGINE": "django.db.backends.mysql", "NAME": "myblog", "USER": "root", "PASSWORD": "your_password", "HOST": "127.0.0.1", "PORT": "3306", } }但要注意,切换到MySQL前,服务器需要装客户端库mysqlclient或PyMySQL,不然Django连接时会报错。
一个隐藏知识点:
NAME用BASE_DIR / "db.sqlite3"这种写法,是因为BASE_DIR是pathlib.Path对象,/运算符是路径拼接。这段路径解析逻辑不必深究,知道它指向项目根目录下的db.sqlite3文件即可。
4.4 LANGUAGE_CODE与TIME_ZONE:困扰很多人的时区问题
Django默认配置是:
LANGUAGE_CODE = "en-us" TIME_ZONE = "UTC"这两个配置看着不起眼,实际影响很大。如果不修改,你的后台、页面显示的语言是英文,时间显示的是UTC时间。国内开发我一般改成:
LANGUAGE_CODE = "zh-hans" TIME_ZONE = "Asia/Shanghai"改完有个注意点:USE_TZ默认是True,意味着Django在数据库里存的是带时区信息的UTC标准时间,展示时才转换成TIME_ZONE指定的本地时间。如果你在代码里直接用datetime.datetime.now(),拿到的是本地时间,但数据库存的是UTC,这会导致时间对不上。
我第一次开发时就是没搞懂这个,发布文章显示的时间总和实际差了8小时。后来学乖了:项目内部统一用django.utils.timezone.now()获取时间,展示时交给模板自动转换。
from django.utils import timezone now = timezone.now()4.5 STATIC与MEDIA:静态文件配置的讲究
全栈项目必然有CSS、JavaScript、图片。Django的静态文件相关配置涉及两个概念:
- STATICFILES_DIRS:开发阶段静态文件存放的目录,一般放在项目目录下的
static/文件夹里。 - STATIC_ROOT:执行
collectstatic命令时,Django把所有app的静态文件收集到一起,用于生产部署。 - MEDIA_ROOT:用户上传的文件(如头像、图片附件)存放的位置。
我常用的配置写法:
STATIC_URL = "/static/" STATICFILES_DIRS = [BASE_DIR / "static"] STATIC_ROOT = BASE_DIR / "staticfiles" MEDIA_URL = "/media/" MEDIA_ROOT = BASE_DIR / "media"这样配置之后,模板里引用静态文件用{% static "css/main.css" %}这种标签,上传的图片通过URL/media/xxx.jpg访问。开发阶段如果用runserver,静态文件会自动映射;部署阶段则要交给Nginx处理,这是后话。
5. 创建App与ORM模型配置:全栈开发的核心动作
5.1 为什么要创建App:管理代码的"分包"思想
执行命令:
python manage.py startapp blog这一步会生成一个blog目录,里面包含models.py、views.py、admin.py、migrations/等文件。App是Django管理功能模块的基本单位。一个项目可以有多个app,比如blog管文章、user管用户、comment管评论,彼此独立又通过配置组合在一起。
我记得早期自己做项目图省事,所有功能都塞在项目自带的配置文件里,一个views.py写了几百行。后来用户量上来、功能变多,根本没法维护。现在我的习惯是一个业务模块一个app,功能边界清晰,删改起来也敢于动手。
创建完app,记得在settings.py的INSTALLED_APPS里加上"blog",这样Django才会把app的模型、命令、模板都加载进来。
5.2 模型定义与数据库迁移
在blog/models.py里定义文章模型:
from django.db import models class Article(models.Model): title = models.CharField(max_length=200) content = models.TextField() pub_date = models.DateTimeField(auto_now_add=True) def __str__(self): return self.title定义好模型后要"让数据库知道",需要执行:
python manage.py makemigrations blog python manage.py migratemakemigrations的作用是生成迁移文件,把模型的变动记录下来;migrate才是真正执行建表或更新表结构。这两步不能省。
auto_now_add=True的意思是:第一次创建对象时自动填入当前时间,之后不再更新。如果想在每次保存时都更新时间,用auto_now=True。两者别搞混。
5.3 用Django Shell验证ORM操作
Django自带一个交互式Shell,可以像Python解释器一样操作数据库。执行:
python manage.py shell然后逐一验证增删改查的功能,例如创建一个对象、查询它、修改它、删除它,这比直接写代码再调试要快得多。我把常用操作列在下面:
from blog.models import Article from django.utils import timezone # 新增 article = Article(title="我的第一篇文章", content="你好,Django") article.save() # 查询 all_articles = Article.objects.all() # 获取单个 a = Article.objects.get(id=1) # 修改 a.title = "新标题" a.save() # 删除 a.delete()删除对象的底层就是执行SQL的DELETE FROM语句。Django的ORM把这一步封装成了一个delete()方法,非常直观。
5.4 注册Admin后台:免费的管理界面
在blog/admin.py里写:
from django.contrib import admin from .models import Article admin.site.register(Article)然后创建超级用户:
python manage.py createsuperuser按提示输入用户名、邮箱、密码,之后重启runserver,访问http://127.0.0.1:8000/admin/,用刚创建的账号登录,就能在浏览器里可视化地管理文章数据了。
这个后台看起来简单,实际上已经具备了增删改查、搜索、分页、权限控制等能力。很多小型项目直接就用Django后台给运营人员用,根本不用额外开发管理界面。
6. 进阶配置场景:用户认证、Cookie与Token
6.1 Django内置用户认证的使用
很多全栈项目需要的"注册登录"功能,Django的auth模块直接提供。创建用户:
from django.contrib.auth.models import User user = User.objects.create_user("jack", "jack@example.com", "password123")装饰器控制视图登录权限:
from django.contrib.auth.decorators import login_required @login_required def dashboard(request): return render(request, "dashboard.html")模板里判断用户是否登录、显示用户名:
{% if user.is_authenticated %} <p>你好,{{ user.username }}!</p> {% else %} <p>请先登录</p> {% endif %}6.2 Cookie设置与Token:一套简单的记忆机制
Session和Cookie解决的问题是:HTTP本身无状态,服务器记不住"这个请求是谁发的"。Cookie相当于服务器发给浏览器的"会员卡",浏览器下次请求时会把卡片带上,服务器靠识别卡片来认出用户。
Django里操作Cookie很简单:
def set_cookie(request): response = HttpResponse("OK") response.set_cookie("username", "jack", max_age=3600) return response def get_cookie(request): username = request.COOKIES.get("username", "") return HttpResponse(f"当前用户:{username}")但Cookie存储登录态有个安全顾虑,数据在客户端可以被篡改。因此Django更推荐用Session——Session内容是存在服务器端的,浏览器只保存一个随机Session ID。刚才提到的SessionMiddleware就是干这个的。
如果用Token认证(比如给移动端App或者前后端分离项目用),比较常见的方案是Django REST Framework的TokenAuthentication,或者用django-rest-knox这类第三方库。把Token放到Cookie里传递时,记得设置HttpOnly属性,防止JavaScript脚本读取Token,降低XSS窃取风险。
6.3 管理后台进阶:Django Unfold初探
如果觉得Django原版Admin界面停留在十年前视觉水平,可以了解一下django-unfold这个第三方主题包。它的安装方式:
pip install django-unfold在INSTALLED_APPS中把它放到admin前面,再设置几项配置即可。它的界面风格更现代,适配暗色模式,还支持自定义侧边栏菜单。对于想把Django后台直接交付给客户使用的团队来说,这个包很值得一试。
7. 常见问题与排查技巧实录
7.1 问题速查表
| 现象 | 排查思路 | 解决方案 |
|---|---|---|
| 端口8000被占用 | 看终端提示,通常有"Error: That port is already in use" | 换个端口:python manage.py runserver 8080;或者lsof -i :8000查进程ID后kill -9 进程ID |
| 迁移时提示"No changes detected" | 模型没改动,或者app没加到INSTALLED_APPS | 检查settings.py;改完模型后再执行makemigrations |
| 模板里静态文件显示不了 | 检查STATIC_URL和模板里load static是否写对 | 模板开头加{% load static %},路径用{% static "..." %} |
| 时间总差8小时 | 时区配置问题 | 确认TIME_ZONE设为"Asia/Shanghai",代码里尽量用timezone.now() |
| 数据库中文乱码 | 数据库本身字符集没设为utf8 | MySQL建库时指定utf8mb4,表也跟随库 |
| 内置后台是英文 | 语言配置没改 | LANGUAGE_CODE = "zh-hans" |
7.2 避坑心得分享
**第一个坑是关于SECRET_KEY的。**我有一次把项目推到一个公开仓库时,不小心把.env文件也推上去了,里面包含生产环境的SECRET_KEY和数据库密码。虽然当天就发现并改了密码,但这件事让我养成了两个习惯:一是在.gitignore里加.env;二是SECRET_KEY这类敏感配置一律从环境变量读取,代码里不写死。
**第二个坑是关于DEBUG开启时静态文件的表现。**开发阶段你甚至可以不配STATICFILES_DIRS,因为runserver会自动按约定找每个app和项目根目录的static/目录。但如果哪天你发现样式突然丢了,先确认路径是否有static/,再确认模板里{% load static %}写没写。
**第三个坑是关于模型迁移的"删字段"操作。**如果你在生产环境里删了模型某个字段,makemigrations会生成一个删除字段的迁移文件。执行migrate时如果这个字段还有数据,Django在部分数据库上会提示确认或者直接失败。我的建议是:删除字段前先备份数据,尤其是有外键关联的表。
第四个坑是我反复踩过多次的:get()查不到或查到多个对象会抛异常。Article.objects.get(id=100)如果数据不存在,抛出DoesNotExist;如果满足条件的不止一条,抛出MultipleObjectsReturned。如果你只是要一个结果,用filter().first()更省心,查不到就返回None,不会中断程序。
7.3 一个完整的初始化流程脚本
结合我多次建项目的经验,这里列一个完整的Django项目初始化操作清单,你照着手敲一遍,就基本串起来了:
mkdir myblog && cd myblog python3 -m venv venv source venv/bin/activate pip install django==5.0.6 django-admin startproject config . python manage.py startapp blog # 编辑 settings.py 添加 blog 到 INSTALLED_APPS,修改时区语言 python manage.py makemigrations python manage.py migrate python manage.py createsuperuser python manage.py runserver这套流程我在新项目里几乎原样执行,跑完就能进入业务开发。
8. 个人体会与进阶方向
每次看到有朋友从零开始搭Django项目,我都提醒他们:不要急着写业务代码,先把配置这块吃透。配置理解了,后面遇到"页面403、时间不对、静态文件加载不了"这类问题,根本不用查搜索引擎,心里就有底了。
另外,Django虽然"全家桶"式省事,但它的设计初衷是拥抱全栈流程,而不是让你完全不需要前端知识。实际开发中,模板渲染、静态资源管理、前后端接口设计,这些你都会面对。如果你想尝试前后端分离——前端用Vue或React,后端只提供API——Django配Django REST Framework同样很顺手,你依然能复用今天讲到的用户认证、模型、Admin后台这些基础能力。
学习Django最忌讳的是"只看不写"。配置项记不住没关系,多建几个项目,每个项目踩一遍坑,你就成了这个框架的老手。希望这篇配置详解能帮你省掉一些我当年绕过的弯路,把精力花在真正有意思的业务逻辑上。