尧图精选

Django全栈开发核心配置与实战:从项目骨架到WebSocket实时推送

🕒 发布时间:2026/10/1 17:29:04 📁 来源:尧图网络
1. 项目引入为什么我把 Django 当作全栈开发的起点不管你是从 Java 转来的老手还是刚啃完 Python 基础语法的新手只要想在 Web 全栈这条路上少踩几个坑Django 基本是绕不开的名字。很多 Django 教程喜欢一上来就抛“MTV 模式”“ORM 映射”“中间件”这些术语读者听完反而更慌。我更愿意换个说法Django 是一个自带数据库操作、后台管理、用户认证和路由映射的“半成品公司”你要做的只是往这个框架里填自己的业务逻辑。这篇文章就是围绕 Django 基本配置和介绍展开的从创建项目、配置数据库、写模型到 WebSocket 实时推送我会把每一步的“为什么”也一起说清楚而不是只丢给你几条命令。这个项目内容适合谁如果你是“django 项目实战新手”想做一个带后台、带登录、带数据管理的完整应用Django 是当前综合成本最低的选择之一如果你已经在做 AI 全栈相关的东西比如训练完 YOLOv11 检测模型后想把结果实时推送到网页Django 也完全扛得住。哪怕你之前学的是 Java 全栈学习路线看完这篇也能快速找到两边概念的一一对应关系。我后面所有配置默认基于 Python 3.10 和 Django 4.x/5.x两者在基本配置上差别不大部分旧教程里的写法我会单独提醒。2. 环境准备与项目骨架搭建2.1 Python 版本与虚拟环境选择动手前一定要先确认 Python 版本。Django 4.x 要求 Python 3.8 以上Django 5.x 则要求 3.10 以上。很多人在这一步栽过跟头系统里装了 Python 2.7或者 Windows 上混装了多个 Python结果执行django-admin命令时完全没反应。我的建议是永远用虚拟环境别把依赖直接装进全局。python3 -m venv venv source venv/bin/activate # Windows 下是 venv\Scripts\activate激活后执行python -V确认版本。接下来安装 Djangopip install django这里有个小细节如果你后续要接数据库驱动、Django Channels、DRF 这些东西建议先把它们一起装了减少反复折腾环境的次数。不过为了讲清楚结构我下面还是按“先骨架后扩展”的顺序来。2.2 创建项目与创建 App 的正确姿势在 Django 里“项目”是一个完整的站点“应用”是站点里的功能模块。一个项目可以包含多个应用这和 Java 里一个 Maven 工程包含多个 module 的思路很像。创建项目标准命令是django-admin startproject myproject .注意最后这个点号。加了点号表示在当前目录生成 manage.py 和 myproject 配置包不加点号Django 会再创建一个 myproject 文件夹套在我当前目录下后面启动服务器时容易路径犯迷糊。我建议你习惯带点号的做法目录层级清爽很多。创建完项目后紧接着创建应用python manage.py startapp blog这就是热搜里那个“django 创建 app”的操作。很多初学者不理解为什么要手动建 app为什么不能直接在根目录写 views.py。原因很简单Django 的自动发现机制、迁移机制、模板和静态文件查找机制都依赖“app 有独立目录”这个约定。一旦你跳过 startapp 自己手写文件夹后面 INSTALLED_APPS、迁移文件、admin 注册全都对不上号排查成本极高。2.3 目录结构到底怎么用创建完成后典型的项目结构是这样myproject/ manage.py myproject/ __init__.py settings.py urls.py asgi.py wsgi.py blog/ __init__.py admin.py apps.py models.py views.py migrations/ venv/settings.py是全局配置中心urls.py是总路由表asgi.py和wsgi.py是部署用的入口后面接 WebSocket 时重点改 asgiblog应用内部再分 models、views、admin 等模块。这个结构是 Django 的“约定优于配置”思想和 Spring Boot 里“约定大于配置”是一个道理你不必急着改它。3. Django 核心配置项逐项拆解3.1 SECRET_KEY、DEBUG、ALLOWED_HOSTS 三兄弟打开settings.py第一眼看到的通常是SECRET_KEY。它用来给 Session、Cookie、CSRF Token、密码重置链接做签名。它的重要性我多说一句一旦泄露攻击者可以伪造会话和 Cookie甚至反推出部分敏感数据。生产环境一定不要把它写死在代码里建议用环境变量引用import os SECRET_KEY os.environ.get(DJANGO_SECRET_KEY, dev-only-insecure-key)DEBUG决定了是否输出详细错误堆栈。开发时设成 True方便看报错部署到公网必须改成 False否则用户能看到你的源码路径、数据库配置等敏感信息这是非常低级却又常见的漏洞。ALLOWED_HOSTS是 Django 内置的 HTTP Host 头校验白名单。当 DEBUGFalse 时如果请求的 Host 不在这个列表里Django 直接返回 400 Bad Request。很多人配置完域名后忘了改这里导致网站打不开ALLOWED_HOSTS [yourdomain.com, www.yourdomain.com, 服务器IP地址]如果可以接受一定风险内网调试时可以写成[*]但公网千万别这么干。3.2 数据库配置从 SQLite 切换到 MySQL 的细节刚创建的项目默认用的是 SQLite这个选择非常适合本地开发零配置文件一个文件就是整个数据库跑测试也快。但真到了企业级项目开发或者你的全栈项目要支撑多个后端实例并发访问SQLite 的并发能力会成瓶颈这时候换成 MySQL 或 PostgreSQL 是必经之路。先看默认配置DATABASES { default: { ENGINE: django.db.backends.sqlite3, NAME: BASE_DIR / db.sqlite3, } }换成 MySQL 后大概是这样DATABASES { default: { ENGINE: django.db.backends.mysql, NAME: mydb, USER: dbuser, PASSWORD: dbpass, HOST: 127.0.0.1, PORT: 3306, OPTIONS: { init_command: SET sql_modeSTRICT_TRANS_TABLES, }, } }光改配置还不够必须装 MySQL 驱动。Django 官方文档推荐mysqlclient安装命令是pip install mysqlclient。Windows 上如果编译报错可以退而求其次用pymysql然后在项目的__init__.py里加一行import pymysql pymysql.install_as_MySQLdb()这里我特别想说迁移到 MySQL 后第一次执行migrate前务必确认数据库本身是 utf8mb4 编码否则中文会变成乱码。创建数据库时用CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;Django 和 MySQL 的交互里字符集问题出现的频率远超你的想象。3.3 多环境配置文件拆分技巧很多 Django 教程把 settings.py 当成一个文件一直用下去但做过企业项目的人会明白开发环境和生产环境的差异实在太大。DEBUG 不同、数据库不同、静态文件处理不同硬塞在一个文件里最终会变成一堆 if 判断。我的习惯是把settings.py改造成一个配置包myproject/settings/ __init__.py base.py dev.py prod.pybase.py放所有环境共用的部分比如 INSTALLED_APPS、AUTH_PASSWORD_VALIDATORS、TEMPLATESdev.py里设置 DEBUGTrue、SQLite 或本地 MySQLprod.py里设置 DEBUGFalse、ALLOWED_HOSTS、数据库密码、日志级别。然后通过环境变量指定使用哪套配置export DJANGO_SETTINGS_MODULEmyproject.settings.prod这样做的好处是部署时只需要改环境变量不用动代码。对新手来说可能稍显复杂但如果你想走“python web 企业级项目开发”这条路这个结构应该尽早养成。3.4 静态文件与媒体文件配置Django 在开发环境处理静态文件非常省事但很多人一部署到 Nginx 就发现图片、CSS 全丢了。核心原因是没理解 STATIC_URL、STATICFILES_DIRS、STATIC_ROOT 三者的关系。项目默认会有STATIC_URL static/它表示浏览器访问静态文件时的 URL 前缀比如/static/style.css。你还可以指定额外的静态文件搜索目录STATICFILES_DIRS [ BASE_DIR / static, ]而STATIC_ROOT是执行collectstatic时的输出目录也就是把所有 app 和 STATICFILES_DIRS 里的静态文件复制到一个地方方便 Nginx 直接托管。生产环境必须要做这一步python manage.py collectstatic如果忘记设置 STATIC_ROOT或设置了但没执行 collectstatic部署后就会出现页面能打开但样式全无的尴尬。媒体文件同样有一套配置MEDIA_URL media/ MEDIA_ROOT BASE_DIR / media开发时要在 urls.py 里加一段来托管 MEDIAfrom django.conf import settings from django.conf.urls.static import static urlpatterns static(settings.MEDIA_URL, document_rootsettings.MEDIA_ROOT)这个只用于开发环境生产环境依然交给 Nginx 或云存储。3.5 语言与时区设置很多国内教程会直接给出这两个配置LANGUAGE_CODE zh-hans TIME_ZONE Asia/Shanghai新手最容易困惑的是USE_TZ。Django 默认 USE_TZTrue意味着数据库里存的是 UTC 时间展示时才转换到当前时区。如果你只修改 TIME_ZONE 而不关心 USE_TZ会出现一个现象后台录入的时间是正确的数据库里看却是相差 8 小时的值。我的建议是新项目直接用 USE_TZTrue这是 Django 推荐的方式再配合前端库做时区转换。如果你做的是纯内部管理系统、且不考虑多时区用户也可以把 USE_TZ 设为 False这样数据库里存的就是本地时间逻辑更直观但要注意 Django 5.x 里有些特性会依赖时区支持混用时要格外小心。4. 数据层模型、迁移与增删改查4.1 定义一个数据模型Django 的 ORM 核心思路是一个 Python 类对应一张数据库表类属性对应表的字段类的实例对应表中的一行。这个设计让数据操作像操作普通对象一样自然。以博客应用为例在 blog/models.py 里定义from django.db import models from django.contrib.auth.models import User class Post(models.Model): title models.CharField(max_length200) content models.TextField() author models.ForeignKey(User, on_deletemodels.CASCADE, related_nameposts) created_at models.DateTimeField(auto_now_addTrue) updated_at models.DateTimeField(auto_nowTrue) def __str__(self): return self.title这里重点解释on_deletemodels.CASCADE它表示当 User 被删除时该用户下的所有 Post 也会被级联删除。这个参数在 Django 2.0 以后强制要求填写因为它直接影响数据完整性。实际项目中要根据业务语义选择 CASCADE、SET_NULL 或 PROTECT比如“用户注销后保留他的文章”就该用 SET_NULL而不是一删全删。4.2 makemigrations 和 migrate 是怎么运作的模型定义完数据库里还没有表。执行python manage.py makemigrationsDjango 会生成一个迁移文件记录“我新增了一个 Post 表字段有哪些”。这个文件是文本化的数据库结构变更历史可以进版本控制。再看一下生成的文件你会发现里面只是描述性的操作列表。接着执行python manage.py migratemigrate 才是真正把变更应用到数据库的命令。它会查看当前数据库里已经执行过哪些迁移记录只执行未见过的迁移文件。这就能理解为什么多环境部署时 migrate 是安全的每个环境都会按需增量执行。养成一个习惯改模型后先 makemigrations再 migrate。不要手动去数据库里改表结构否则迁移记录和实际 schema 对不上后面排查会非常痛苦。4.3 如何用 Django 执行查询-删除对象热搜里有一条“django 执行查询-删除对象”这其实是 ORM 使用频率最高的操作。先说查询。最基础的是全量查询all_posts Post.objects.all()带条件过滤用 filter多个条件是 AND 关系django_posts Post.objects.filter(title__containsDjango, author__isnullFalse)只想取一条且确定存在时用 get但注意 get 查不到会抛DoesNotExist查到多条会抛MultipleObjectsReturned建议配合 try 或使用get_object_or_404from django.shortcuts import get_object_or_404 post get_object_or_404(Post, id1)新增数据和更新数据同样直观post Post(titleDjango 全栈入门, content..., authorsome_user) post.save() post.title Django 全栈入门修订版 post.save() # 只有字段有变化时才真正执行 UPDATE批量更新可以用 QuerySet 的 update 方法它只发一条 SQLPost.objects.filter(author__usernameadmin).update(title被批量修改)删除对象有三个层次。单个实例删除post Post.objects.get(id1) post.delete()QuerySet 批量删除Post.objects.filter(created_at__year2020).delete()这种删除是逐条删除的如果有外键关联的字段Django 会额外处理关联对象所以批量删除时要评估数据量量大了建议改成软删除方案即增加一个 is_active 字段查询时默认过滤掉而不是物理删表。5. 视图、路由与模板的串接5.1 URLconf 的配置习惯Django 的路由配置集中在 urls.py。项目和 app 各有自己的 urls.py项目层用 include 引入 app 路由这种分层结构和 Java 里“网关路由-服务路由”的思想类似。看一个例子from django.contrib import admin from django.urls import path, include urlpatterns [ path(admin/, admin.site.urls), path(blog/, include(blog.urls)), ]然后在 blog/urls.py 里写具体路由from django.urls import path from . import views urlpatterns [ path(, views.index, nameblog_index), path(post/int:pk/, views.post_detail, namepost_detail), ]int:pk是路径转换器的用法它能把 URL 里的数字自动转成 int 并传给视图。给路由起 name 很重要模板里可以用{% url post_detail pkpost.pk %}反向解析 URL这样以后改 URL 规则模板和视图里的引用会自动跟着变不用全局搜索手工替换。5.2 视图里到底返回什么视图函数的职责是“接收请求返回响应”。最简单的视图返回 HttpResponse传入一段 HTML 字符串但这不适用于复杂页面。更常见的是用 render 渲染模板from django.shortcuts import render def index(request): posts Post.objects.all() return render(request, blog/index.html, {posts: posts})做前后端分离时视图要返回 JSON这时候用 JsonResponsefrom django.http import JsonResponse def api_posts(request): posts Post.objects.all().values(id, title) return JsonResponse(list(posts), safeFalse)这里要把 QuerySet 转成 list否则 JsonResponse 无法直接序列化。这是新手容易踩的坑。视图里做跳转也很常见from django.shortcuts import redirect def redirect_view(request): return redirect(blog_index)5.3 模板引擎怎么用Django 自带模板引擎语法和 Vue、React 差别很大但骨子里都是“把数据替换到页面上”。最常用的是三组语法{% extends base.html %} {% block content %} h1{{ post.title }}/h1 p{{ post.content }}/p {% for item in list_items %} span{{ item }}/span {% endfor %} {% endblock %}在“全栈”视角下模板就是 Django 负责的服务端渲染方案。如果项目走前后端分离你可以完全不用模板只返回 JSON前端再用 React 或 Vue 消费接口。但如果你一个人做全栈或者团队很小服务端模板能极大减少接口定义和联调成本。模板里加载静态文件也很讲究{% load static %} img src{% static images/logo.png %} alt这行代码会按照 STATIC_URL 生成静态资源地址。再次提醒部署后这块特别容易出问题。6. 后端数据实时推送WebSocket 在 Django 里的正确实现6.1 为什么不用轮询全栈项目一旦需要“后台有数据前端立刻展示”很多人第一反应是写定时器轮询接口。轮询确实简单但代价很大连接频繁建立销毁服务器响应大量无效请求实时性还有延迟。更合适的方案是 WebSocket它是一条持久连接服务端可以主动把数据推给浏览器延迟能降到毫秒级。Django 默认是 WSGI 模式处理同步 HTTP 没问题但 WebSocket 是长连接需要异步能力和协议升级处理。这就是 Django Channels 要解决的问题。它让 Django 同时支持 WebSocket、聊天机器人、消息推送这类实时场景也是“python django websocket 实现后台有数据前端推送”这个热搜背后的标准答案。6.2 接入步骤安装 Channels 与配置 ASGI第一步安装依赖pip install channels daphnedaphne是 Channels 官方推荐的 ASGI 服务器生产环境可以直接用它替掉 gunicorn 的异步部分。第二步修改 settings.py。把 daphne 放到 INSTALLED_APPS 最前面然后是 channels。因为 daphne 要覆盖掉 runserver 的默认 WSGI 启动逻辑INSTALLED_APPS [ daphne, django.contrib.admin, django.contrib.auth, ... channels, blog, ] ASGI_APPLICATION myproject.asgi.application CHANNEL_LAYERS { default: { BACKEND: channels.layers.InMemoryChannelLayer, } }InMemoryChannelLayer 适合本地开发不跨进程。部署时如果跑了多个 worker 进程要换成 RedisCHANNEL_LAYERS { default: { BACKEND: channels_redis.core.RedisChannelLayer, CONFIG: {hosts: [(127.0.0.1, 6379)]}, } }第三步修改 asgi.py让它同时处理 HTTP 和 WebSocketimport os from django.core.asgi import get_asgi_application from channels.routing import ProtocolTypeRouter, URLRouter from channels.auth import AuthMiddlewareStack from django.urls import path from blog.consumers import BlogConsumer os.environ.setdefault(DJANGO_SETTINGS_MODULE, myproject.settings) django_asgi_app get_asgi_application() websocket_urlpatterns [ path(ws/blog/, BlogConsumer.as_asgi()), ] application ProtocolTypeRouter({ http: django_asgi_app, websocket: AuthMiddlewareStack(URLRouter(websocket_urlpatterns)), })第四步写 consumer。consumer 是 Django Channels 里处理 WebSocket 消息的逻辑单元类似视图之于 HTTP。在 blog/consumers.py 里import json from channels.generic.websocket import AsyncWebsocketConsumer class BlogConsumer(AsyncWebsocketConsumer): async def connect(self): self.group_name blog_updates await self.channel_layer.group_add(self.group_name, self.channel_name) await self.accept() async def disconnect(self, code): await self.channel_layer.group_discard(self.group_name, self.channel_name) async def receive(self, text_data): data json.loads(text_data) message data.get(message, ) # 把消息广播给组内所有客户端 await self.channel_layer.group_send( self.group_name, {type: blog_update, message: message}, ) async def blog_update(self, event): await self.send(text_datajson.dumps({message: event[message]}))这里的关键点是group_add和group_send。group 相当于一个消息广播频道任意后端代码都可以往这个频道发消息所有连接了该频道的浏览器都会立刻收到。这就是实现“后台有数据前端推送”的核心机制。前端 JavaScript 侧的长连接写法是const socket new WebSocket(ws://你的域名/ws/blog/); socket.onmessage function (event) { const data JSON.parse(event.data); // 动态更新页面 DOM };6.3 一个实际场景YOLOv11 检测结果实时推送到前端我最近在做一个 AI 全栈项目后台用 YOLOv11 做目标检测检测完的结果需要实时显示在网页监控面板上。如果每隔一秒轮询一次 Flask 或 Django 接口图片数据多时带宽扛不住显示也不够即时。后来我改成 Channels 方案YOLOv11 推理线程拿到检测结果后不直接写数据库而是通过 channel_layer.group_send 发到前端浏览器的画布组件立刻更新框选坐标。具体链路是摄像头抽帧 - YOLOv11 推理 - 后台处理线程 - channel_layer.group_send - 浏览器 WebSocket 接收 - Canvas 绘制这种模式对物联网监控、数据大屏、消息通知这类场景都适用。你不需要真正去跑 YOLOv11只要理解了“后端任意位置都能通过 channel_layer 推送数据到指定前端组”这个模型就知道 Channels 在 Django 全栈里的分量了。7. 登录态与 Cookie / Token 的安全配置7.1 Django 内置 Session-Cookie 机制Django 自带的认证系统默认用 Session 记录登录状态。用户登录成功后服务端把 session 数据存到数据库或缓存同时向浏览器写一个名为 sessionid 的 Cookie。浏览器后续请求都带着这个 CookieDjango 再通过 sessionid 找到对应会话。设置登录状态通常是用内置的 login 函数或者视图里手动写入 sessiondef login_view(request): user authenticate(request, username..., password...) login(request, user) return redirect(index)如果你需要在响应里自定义 Cookie可以这样做response redirect(index) response.set_cookie(user_source, wechat, max_age3600) return response读取 Cookie 可以直接从 request.COOKIES 字典里取user_source request.COOKIES.get(user_source)7.2 DRF JWT 时把 Token 放进 Cookie当项目走向前后端分离Django 后台往往只提供 JSON API这时候认证方案常用 JWT。JWT 可以放在请求头 Authorization 里也可以放在 Cookie 里。用 Cookie 的好处是可以用 HttpOnly 属性让 JavaScript 读不到 Token从根本上降低 XSS 窃取 Token 的风险。在登录接口里生成 Token 并写入 Cookiefrom django.http import JsonResponse import jwt def login_api(request): # 验证用户名密码成功后 token jwt.encode({user_id: user.id, exp: ...}, SECRET, algorithmHS256) response JsonResponse({code: 0, message: ok}) response.set_cookie( access_token, token, max_age7 * 24 * 3600, httponlyTrue, samesiteLax, securerequest.is_secure(), path/, ) return response注意securerequest.is_secure()如果网站是 HTTPSCookie 必须带 Secure 标志否则浏览器会在 HTTPS 页面拒绝写入非安全 Cookie。samesiteLax是为了防止跨站请求携带 Cookie这是 CSRF 防御的重要一环。读取这个 Cookie 也简单token request.COOKIES.get(access_token)7.3 CSRF 保护机制Django 对 CSRF 的防御思路是给每个客户端生成一个随机的 csrftoken写入 Cookie真正提交表单或者发 POST 请求时必须把这个 token 一并提交服务端比对两者是否一致。在服务端模板渲染的页面里表单要加一行form methodpost {% csrf_token %} ... /form前后端分离下前端 JavaScript 发送 POST 请求时要从浏览器 Cookie 里读取 csrftoken然后放入请求头const csrfToken document.cookie.match(/csrftoken([^;])/)[1]; fetch(/api/create/, { method: POST, headers: { X-CSRFToken: csrfToken, Content-Type: application/json, }, body: JSON.stringify({ title: test }), });如果你设置了CSRF_COOKIE_HTTPONLY TrueJavaScript 就读不到这个 Cookie 了这种情况下通常改用前端框架从接口获取 CSRF Token 或者关闭 CSRF仅限内部无状态 API。实际项目中我会把需要登录的 API 走 JWT把不需要登录的公开接口配上 CSRF 豁免但要严格限制请求来源否则等于开了个口子。8. Admin 后台与生态扩展8.1 内置 admin 系统能干什么Django 最吸引全栈新手的一点就是自带后台。你没看错只要配置好数据库、创建了模型后台管理页面几乎是零代码生成的。运行python manage.py runserver访问/admin/输入超级管理员账号createsuperuser命令创建就能增删改查所有注册模型。在 blog/admin.py 里注册from django.contrib import admin from .models import Post admin.register(Post) class PostAdmin(admin.ModelAdmin): list_display [id, title, author, created_at] list_filter [created_at, author] search_fields [title]这三个配置非常实用list_display 控制列表展示哪些列list_filter 在右侧生成筛选器search_fields 提供搜索框。对内容管理系统来说后台做出来等于完成了一半业务。8.2 试试 Django Unfold 这类现代后台主题内置 admin 功能虽强但界面停留在十几年前的审美。如果你希望后台颜值高一点、操作体验现代化一点可以在 GitHub 上找找 Django Unfold。它是一套基于 Tailwind 的 Django Admin 主题安装后在 INSTALLED_APPS 里把 unfold 放到 django.contrib.admin 前面即可INSTALLED_APPS [ unfold, django.contrib.admin, ... ]它会自动接管 admin 的样式和部分交互提供侧边栏、表单卡片、暗色模式。我的经验是给客户演示项目时这样一个后台主题就能让整体观感提升一个档次很多非技术客户根本不会在意你是用 Django 还是别的框架做的他们只看界面。8.3 企业级扩展如何配讲完基本配置顺便提一下“企业级项目”常搭配哪些组件。数据库迁移用 Django 自带接口文档可以集 drf-spectacular自动生成 Swagger/OpenAPI 文档后台任务用 Celery Redis日志配置在 settings.py 里写 LOGGING异常收集可以接 Sentry。这套组合基本覆盖了“python web 企业级项目开发教程Django 版”这个方向的主要内容。日志配置尤其容易忽略。开发时控制台能看堆栈生产环境一关 DEBUG报错就没了。最少要配一个文件日志LOGGING { version: 1, disable_existing_loggers: False, handlers: { file: { class: logging.FileHandler, filename: logs/app.log, }, }, root: { handlers: [file], level: INFO, }, }错误日志留痕是排查线上问题的第一道防线。9. 常见问题与排查速查表我自己在配 Django 基本配置的过程中踩过不少坑也帮别人排查过很多次最常见的几个问题基本是固定的。整理成一个速查表现象典型原因解决办法页面显示 Bad Request (400)ALLOWED_HOSTS 没配当前域名或 IP把域名/IP 加进 ALLOWED_HOSTS后台能开但 CSS 全丢STATIC_ROOT/STATIC_URL 配置错误或没执行 collectstatic检查静态文件配置重新 collectstatic表单提交报 403 CSRF模板少了{% csrf_token %}或前端没带 X-CSRFToken 请求头在表单里加 token前端 JS 手动附带请求头迁移时报“Table already exists”数据库里有残留表结构迁移记录不一致不轻易删表先备份后同步迁移记录必要时用migrate --fake中文保存后变问号数据库或表不是 utf8mb4 编码建库时指定 CHARACTER SET utf8mb4WebSocket 连不上没配 ASGI_APPLICATION或没有用支持 ASGI 的服务器启动检查 settings 和 asgi.py用 daphne 启动多进程下消息推送时灵时不灵用了 InMemoryChannelLayer换成 Redis Channel LayerCookie 写不进去Secure 和 HTTPS 不匹配或 SameSite 属性太严格根据实际情况调整 Secure/SameSite9.2 排除问题的通用思路遇到 Django 问题我一般按三层排查第一层看 Django 日志第二层看浏览器开发者工具 Network 面板第三层看数据库实际内容。绝大多数新手问题出在第一和第二层之间日志写着 400/403/404浏览器里只看到“服务器错误”或一段看不懂的英文实际上把日志打开一眼就能定位。再补充一个我自己的习惯开发环境一定要开 DEBUGTrue然后接一个 SQLite 的只读副本随时随地用 Django Shell 调试数据。python manage.py shell在 shell 里可以测试所有 ORM 查询和模型方法比反复改视图后刷新页面快太多。比如想知道某条查询会生成什么 SQL直接打印 QuerySet 的.queryqs Post.objects.filter(author__usernameadmin) print(qs.query)这是排查“查询结果和预期不一致”最有效的工具。9.3 一些容易被忽略的安全配置最后提几个安全相关配置日常绝对用得上SESSION_COOKIE_HTTPONLY True CSRF_COOKIE_HTTPONLY True SECURE_SSL_REDIRECT False # 生产环境开启后强制 HTTPS X_FRAME_OPTIONS DENYSESSION_COOKIE_HTTPONLY 让 JavaScript 读不到 sessionid可以防范大部分 XSS 窃取会话X_FRAME_OPTIONS 是防止点击劫持的开关。这些配置不复杂但很多入门级项目都没开等你部署上线再补往往就要面对一堆历史兼容问题。我个人的体会是Django 的“基本配置”远不止改改 settings.py 那么简单它背后是一整套关于安全、数据库、路由、异步通信的约定。把这些配置吃透之后无论是继续扩展 REST API、接入 Celery 任务队列还是把 YOLOv11 这类 AI 能力揉进全栈应用都会顺很多。你最需要建立的不是背命令而是遇到现象时能快速判断问题出在哪一层是路由没进来、数据库没迁移、静态文件没收集还是 WebSocket 握手失败。一旦有了这个排查框架Django 对你来说就不再是“配置麻烦”的框架而是一个真正能帮你落地的全栈底座。最后再分享一个小技巧给项目写一个 README里面记录从克隆代码到启动服务的完整命令。你会感谢自己有这个习惯的因为三个月后你再回来看这个 Django 项目能帮你回忆起一切的往往不是代码注释而是当时随手记下的配置步骤。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →