资讯动态

Django Web项目从零搭建:源码解析与避坑指南

发布时间:2026/10/20 15:13:52 来源:尧图企业网站定制
简介这是一份基于Python的简单Django Web项目源码是一个定位清晰的Web开发入门级学习工程尤其适合刚接触Django框架、想快速得到一个可运行网站基础功能的开发者对于正在完成课程设计或毕业设计的学生也可以直接作为基础模块进行参考和二次开发。项目围绕用户登录与页面渲染展开通过实际可运行的代码展示了配置文件、URL路由映射、视图函数、数据模型和HTML模板之间的标准协作方式帮助初学者直观理解一次请求从浏览器到达服务器、经视图逻辑处理后返回页面的完整链路。资源以zip格式打包共40个文件主要包含13个Python源码文件、24个Python编译缓存文件、1个HTML页面模板、1个SQLite数据库文件和1份说明文档整体占用空间仅155KB文件精简而结构完整下载后可快速在本地Python环境中打开查看。目前已有480人学习或下载。通过仔细阅读源码读者可以掌握Django工程初始化、ORM模型定义、后台管理配置、路由编写、模板渲染等关键技能同时还可以直接运行项目尝试调整登录校验规则、修改页面样式或新增数据库字段在动手调试中建立对框架各层协作机制的直观印象为独立开发更完整的Web应用打下良好基础。1. 从一个空目录到能访问的Django页面这个项目源码到底在解决什么如果你搜到这个标题大概率不是想听Django有多强大而是手头有个课程设计、毕业设计或者公司内部小工具的需求需要一个“能跑、能改、能交差”的起点。所谓“基于Python的简单Django Web项目设计源码”说白了就是一套用Django搭起来的最小但完整的Web应用骨架有页面、有数据库、有表单提交、有后台管理代码量控制在几百行以内新手拿到后能看懂每个文件在干什么改一改就能变成自己的项目。我用这个思路做过不少类似的东西包括给某高校实训课写的课程管理Demo给某公司内部做的会议室预订小工具。它们的共同点是不需要高并发、不需要分布式核心诉求是“一周内上线、三个月内有人用、后续能维护”。这篇文章把我验证过的目录结构、参数配置和踩过的坑完整写出来你照着做从零到一个能访问的Django应用大概需要一个小时。2. 搭好Django最小可运行环境从解释器版本到第一个“它活了”的请求2.1 为什么“简单Django项目”也要从venv开始很多新手图省事直接用全局Python环境装Django装完发现系统里其他脚本跑不了了或者Django版本和项目要求对不上。我习惯的做法是每个项目一个虚拟环境这是后面所有操作不出乱子的前提。# Python 3.8 及以上版本都自带venv模块 python3 -m venv venv # 激活虚拟环境Windows下执行 venv\Scripts\activate source venv/bin/activate # 安装Django这里固定大版本避免未来升级导致行为变化 pip install django4.2,5.0激活后命令行前面会出现(venv)前缀这说明你已经在隔离环境里。安装完成后用python -m django --version确认版本我一般要求4.2 LTS版本它支持到2026年比追最新版稳得多。参数说明venv是虚拟环境目录名可以随便起但建议用venv因为.gitignore里通常默认忽略它。Python版本建议3.9或3.113.10有个match语法和某些库的兼容问题虽然Django本身没坑但后续你要装其他依赖时3.11更稳。这里有个常见误区不要用pip install django直接装最新版。Django每年发两个版本最新版往往是“尝鲜版”文档和第三方库的适配还没跟上。锁定4.2,5.0的意思是装4.2系列的最新补丁版这是生产环境验证过的组合。2.2 创建项目和Appstartproject与startapp的分工逻辑Django把“项目”和“应用”分成两个概念这是新手最容易懵的地方。项目是一个网站的全局配置应用是里面的一个功能模块。一个项目可以挂多个应用比如一个商城项目里有“用户”“商品”“订单”三个应用。# 创建项目名字用纯英文小写 django-admin startproject mysite cd mysite # 创建应用vote是“投票”功能模块 python manage.py startapp vote执行后你的目录结构是这样mysite/ ├── manage.py # 项目管理入口所有命令都通过它执行 ├── mysite/ # 全局配置目录 │ ├── settings.py # 项目配置文件 │ ├── urls.py # 根路由配置 │ └── wsgi.py # 部署入口 └── vote/ # 应用目录 ├── models.py # 数据模型 ├── views.py # 业务逻辑 ├── urls.py # 应用自己的路由 └── migrations/ # 数据库迁移记录为什么要分这么细因为Django的哲学是“可插拔”。你以后做第二个项目时可以直接把vote这个目录拷过去只要配置好路由就能复用。我见过把全部代码塞进一个views.py的项目三个月后自己都找不到逻辑在哪。按模块拆分文件是对未来自己的仁慈。注意startapp不会自动帮你建urls.py需要手动创建。这是Django一个容易漏掉的细节后面路由配置时我还会提。2.3 让第一个页面跑起来urls、views、settings三处联动Django处理一个请求的流程很直接浏览器发请求到URL路由路由分发给视图函数视图函数处理后返回响应。三个文件必须同时配好才能看到页面。先在vote/views.py里写一个最简单的视图from django.http import HttpResponse def index(request): return HttpResponse(欢迎来到投票系统)然后在vote/目录下新建urls.pyfrom django.urls import path from . import views # app_name用于模板中反向解析URL多应用时避免链接写错 app_name vote urlpatterns [ # 第一个参数是空字符串表示匹配该应用下的根路径 path(, views.index, nameindex), ]最后修改全局路由mysite/urls.py把应用挂上去from django.contrib import admin from django.urls import include, path urlpatterns [ path(admin/, admin.site.urls), # 任何以vote/开头的请求都交给vote应用的urls.py处理 path(vote/, include(vote.urls)), ]启动开发服务器python manage.py runserver浏览器访问http://127.0.0.1:8000/vote/看到“欢迎来到投票系统”就说明通了。参数说明include()的作用是把子路由的匹配责任转交给应用这样全局路由文件保持干净。nameindex给这个URL起了名字以后模板里写{% url vote:index %}比硬编码路径更安全——路径改了模板不用改。这三个文件是Django请求链路的铁三角不管项目多复杂本质都是这个结构在重复。3. 把“简单”做成“完整”核心模块与源码目录设计的落地写法3.1 数据模型先行用投票/待办这类经典模型把ORM跑通一个Web项目如果只有静态页面那根本不叫Web项目。Django的价值在于它的ORM对象关系映射——你写Python类它自动帮你生成数据库表。设计模型时记住一个原则先想清楚业务对象和它们的关系再动手写代码。以投票系统为例两个核心模型问题Question和选项Choice。一个问题有多个选项一个选项属于一个问题这是典型的一对多关系。# vote/models.py from django.db import models class Question(models.Model): question_text models.CharField(max_length200, verbose_name问题内容) pub_date models.DateTimeField(verbose_name发布日期) def __str__(self): return self.question_text class Choice(models.Model): question models.ForeignKey(Question, on_deletemodels.CASCADE, verbose_name所属问题) choice_text models.CharField(max_length200, verbose_name选项内容) votes models.IntegerField(default0, verbose_name票数) def __str__(self): return self.choice_text写完模型后执行两条命令让数据库结构生效# 生成迁移文件相当于记录“我要建这两张表” python manage.py makemigrations vote # 执行迁移真正在数据库里建表 python manage.py migrate逻辑说明makemigrations是Django特有的“版本控制”机制它把模型变化记录到migrations/目录下而不是直接改数据库。好处是你可以回滚、可以代码审查、可以多环境同步。migrate则是把迁移记录应用到实际数据库。参数说明on_deletemodels.CASCADE表示问题被删除时它的所有选项也跟着删除这是外键的级联删除行为。如果你不想删选项可以用SET_NULL配合nullTrue或PROTECT有选项时禁止删问题。默认的SQLite数据库文件会在项目根目录自动生成不需要你手动创建但注意.gitignore里要加上db.sqlite3否则提交代码时会把测试数据一起提交。3.2 视图层选函数还是类单人维护时怎么选更稳Django视图有两种写法函数视图FBV和类视图CBV。新手看到教程里两种都有容易纠结。我的建议很直白项目逻辑简单、你自己维护就老老实实用函数视图。函数视图的流程是线性的从上往下读就行类视图把GET、POST拆成类方法抽象度更高适合逻辑复杂的场景但报错时堆栈追踪会多绕一层。以投票详情页为例函数视图长这样from django.shortcuts import get_object_or_404, render from .models import Question def detail(request, question_id): # 尝试取问题不存在时返回404而不是报500错误 question get_object_or_404(Question, pkquestion_id) return render(request, vote/detail.html, {question: question})对应路由# vote/urls.py path(question/int:question_id/, views.detail, namedetail),参数说明int:question_id是Django的路径转换器它匹配一个整数并作为参数传给视图函数。这样URL从/vote/question/3/到视图函数的question_id3类型转换自动完成。如果是字符串可以用str:slug但能定成int就别用str省得在视图里做类型判断。类视图版本只是换了个写法效果相同。如果你想省事又想保持可读性还可以在函数视图上装饰require_GET或require_POST比在函数内部判断request.method干净得多。3.3 后台管理注册模型后白拿的增删改查Django自带一个后台管理界面这是它比起其他框架最“香”的特性——业务数据的管理后台不用写一行CRUD代码。前提是你在admin.py里注册模型。# vote/admin.py from django.contrib import admin from .models import Question, Choice # 注册模型让它们在后台可见 admin.site.register(Question) admin.site.register(Choice)还需要创建一个管理员账号python manage.py createsuperuser # 按提示输入用户名、邮箱、密码访问http://127.0.0.1:8000/admin/登录后就能看到“问题”和“选项”两张表的增删改查界面。逻辑说明admin.site.register是最简单的注册方式适合模型少、字段不复杂的场景。如果你要给字段加搜索、加筛选可以定义ModelAdmin类admin.register(Question) class QuestionAdmin(admin.ModelAdmin): list_display [question_text, pub_date] search_fields [question_text] list_filter [pub_date]参数说明list_display控制后台列表页显示哪些列search_fields开启搜索框按字段模糊查询list_filter在右侧生成日期筛选器。这三个参数是后端管理中最常用的能覆盖80%的需求。注意createsuperuser创建的账号存在数据库里如果数据库文件被删除比如你重置了项目账号也没了需要重新创建。这是开发期常遇到的情况不算bug。3.4 源码文件清单与各文件职责一个“简单”Django项目的源码文件并不多但每个文件都有明确职责。新手拿到别人的项目源码第一步应该是先看文件结构而不是打开某个代码文件硬读。我习惯的阅读顺序是先看settings.py了解项目配置再看根urls.py了解有哪些路由然后按路由逐个进App看views.py和models.py。文件路径职责新手常犯错误manage.py所有Django命令的入口不修改保持默认mysite/settings.py全局配置App列表、数据库、模板、静态文件忘记把新App加入INSTALLED_APPSmysite/urls.py根路由分发不写include导致子路由不生效vote/models.py定义数据模型模型改了不makemigrationsvote/views.py业务逻辑处理忘记from django.shortcuts import rendervote/admin.py后台管理注册不注册后台看不到数据表templates/HTML模板模板目录配置错误导致模板找不到INSTALLED_APPS这个配置项是Django的“插件列表”每新建一个App都必须把它加进去否则Django不认识这个应用。这个错误排在避坑榜第一位# mysite/settings.py INSTALLED_APPS [ django.contrib.admin, django.contrib.auth, django.contrib.contenttypes, django.contrib.sessions, django.contrib.messages, django.contrib.staticfiles, # 新增这行你的应用 vote, ]我见过有人在这个列表里漏掉django.contrib.staticfiles结果静态文件功能一直报错。系统自带应用尽量全保留它们之间有依赖关系——django.contrib.admin依赖auth、contenttypes等模块删除任何一个都可能导致后台崩溃。4. 模板与静态资源让页面不是白底黑字的三个关键设置4.1 模板继承base.html与block的玩法新手写Django模板最容易犯的错误是每个页面从头写一个完整的HTML复制粘贴head和导航栏。正确的做法是用模板继承写一个base.html作为骨架子页面只填自己特有的内容块。!-- templates/base.html -- !DOCTYPE html html head meta charsetUTF-8 title{% block title %}默认标题{% endblock %}/title /head body nav a href{% url vote:index %}首页/a /nav main {% block content %} !-- 子模板将覆盖这里 -- {% endblock %} /main /body /html然后在模板目录下建一个和App同名的子目录避免不同App间的模板文件重名——Django的模板引擎是多App共享一个目录的不加命名空间会互相覆盖。这又是新手容易踩的坑。!-- templates/vote/detail.html -- {% extends base.html %} {% block title %}{{ question.question_text }} - 投票{% endblock %} {% block content %} h1{{ question.question_text }}/h1 form action{% url vote:vote question.id %} methodpost {% csrf_token %} {% for choice in question.choice_set.all %} label input typeradio namechoice value{{ choice.id }} {{ choice.choice_text }} /labelbr {% endfor %} button typesubmit投票/button /form {% endblock %}逻辑说明{% extends base.html %}声明继承{% block content %}和{% endblock %}定义了一个可覆盖的区域。子模板里同名block的内容会替换父模板的默认内容。没有写在block里的内容不会显示——这是新手最容易疑惑的地方以为子模板内容会自动拼进去其实必须显式放在block里。{{ question.choice_set.all }}是Django ORM的反向查询一个Question对象可以通过choice_set访问它关联的所有Choice对象。如果你给外键字段加了related_namechoices那写法就是question.choices.all()更简洁。4.2 静态文件按App隔离css/js/images的目录约定Django的静态文件CSS、JS、图片有一个约定每个App下建一个static/app_name/目录项目级的静态文件放在根目录static/下。这样Django能自动找到它们不会撞名。/* vote/static/vote/style.css */ body { font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; }在模板中加载静态文件!-- 在base.html的head区域加入 -- {% load static %} link relstylesheet href{% static vote/style.css %}对应settings.py配置# mysite/settings.py STATIC_URL /static/ # 开启DEBUG时Django自动从各App的static目录寻找静态文件 # 关闭DEBUG后需要用collectstatic命令收集到一处统一提供 STATIC_ROOT BASE_DIR / staticfiles参数说明STATIC_URL是浏览器访问静态文件的URL前缀一般保持/static/不变。STATIC_ROOT只在部署时有用python manage.py collectstatic会把所有App和项目里的静态文件复制到这个目录交给Nginx等服务器统一托管。我在开发期不会刻意配STATICFILES_DIRS因为各App的static/目录已经是默认搜索路径。只有当你需要把某个不属于任何App的静态目录比如项目根目录下的assets/也纳入管理时才需要加它。4.3 表单与CSRFPOST请求必踩的一关Django的CSRF防护是安全的一大卖点但也是新手第一次写POST表单时必然撞到的墙——不加{% csrf_token %}就提交返回403错误。这个机制的原理是服务器生成一个随机token放进表单隐藏域提交时校验。攻击者无法跨域伪造这个token所以能有效防止跨站请求伪造。form action{% url vote:vote question.id %} methodpost {% csrf_token %} !-- 表单内容 -- /form对应的视图处理from django.shortcuts import get_object_or_404, redirect from django.http import HttpResponseRedirect from django.urls import reverse from .models import Choice, Question def vote(request, question_id): question get_object_or_404(Question, pkquestion_id) try: selected_choice question.choice_set.get(pkrequest.POST[choice]) except (KeyError, Choice.DoesNotExist): # 重新渲染详情页并带一个错误提示 return render(request, vote/detail.html, { question: question, error_message: 你没有选择任何选项。, }) else: selected_choice.votes 1 selected_choice.save() # POST成功后重定向避免刷新页面时重复提交 return HttpResponseRedirect(reverse(vote:results, args(question.id,)))逻辑说明这是Django官方投票教程的规范化写法三个细节值得记。第一处理POST的视图必须用HttpResponseRedirect或redirect返回而不是直接render这遵循“POST-重定向-GET”模式防止用户刷新页面时表单重复提交。第二request.POST[choice]用下标取值key不存在会抛KeyError所以要用try包住。第三投票成功后在else分支里操作数据库save()才真正写入。参数说明reverse(vote:results, args(question.id,))是“反向解析URL”——根据路由名称和参数生成完整URL字符串。这样做的好处是如果以后改了URL路径代码和模板里的链接不用跟着改统一由路由表管控。坑点是路由里的name必须唯一多个App里出现同名name会互相覆盖所以app_name vote这个命名空间就发挥作用了。5. Django项目避坑指南新人最常翻车的5个真实案例5.1 迁移报错“No changes detected”——模型改了但没生成迁移文件现象你改了models.py加了几个字段执行python manage.py makemigrations却提示No changes detected。原因最常见的是App没有加进INSTALLED_APPSDjango根本不扫描这个应用的模型。另一个可能是你在错误的目录下执行命令——改模型时要先cd到包含manage.py的项目根目录否则命令找不到项目。解决第一步检查settings.py的INSTALLED_APPS里有没有你的App名。第二步确认你当前在manage.py所在目录。如果都是对的试着执行python manage.py makemigrations 应用名显式指定AppDjango会给出更详细的提示。5.2 静态文件404——DEBUGFalse后图片和样式全丢现象开发阶段一切正常一旦设置DEBUG False页面样式全乱、图片显示不出来。原因Django只在DEBUGTrue时自动托管静态文件通过runserver。生产环境下runserver不会提供静态文件必须用collectstatic收集后交给专门服务器或者用中间件处理。解决如果你只是本地演示不想配Nginx最简单的方式是保持DEBUG True仅限本地/内网演示把ALLOWED_HOSTS配好。如果一定要关调试执行python manage.py collectstatic确认STATIC_ROOT目录下有文件再用中间件方式托管# 安装whitenoise后在settings.py的MIDDLEWARE中加入 # whitenoise.middleware.WhiteNoiseMiddleware放在SecurityMiddleware之后 # 并设置 STATICFILES_STORAGE whitenoise.storage.CompressedManifestStaticFilesStorage5.3 表单提交403——CSRF验证失败的三个原因现象表单一提交就报CSRF verification failed或者后台登录页面也报403。原因三种情况最常见。一是模板里忘了{% csrf_token %}。二是MIDDLEWARE配置里把CsrfViewMiddleware删了或放错了位置。三是请求头缺少Referer某些浏览器插件或代理会去掉它。解决第一检查模板加上{% csrf_token %}。第二检查MIDDLEWARE数组确保django.middleware.csrf.CsrfViewMiddleware存在。第三如果开发时用了HTTP而非HTTPS检查浏览器是否设置了“发送严格Referrer”策略必要时在settings里加CSRF_TRUSTED_ORIGINS。5.4 时区与时间显示差8小时现象在后台发布一条记录列表页显示的时间和本地时间不一致差8个小时。原因Django默认的TIME_ZONE UTC数据库存的是UTC时间页面显示时没做转换。中国用户打开后台看到的时间比北京时间晚8小时。解决把settings.py里的TIME_ZONE改成Asia/Shanghai并把USE_TZ保持为True不建议关掉Django的时区系统是设计好的关掉会埋下隐患。TIME_ZONE Asia/Shanghai USE_TZ True注意改完后已存在数据库里的时间不会自动转换只会影响新写入的数据。开发期数据无所谓的但如果是正式数据需要手动做一次迁移更新。5.5 端口被占用或“That port is already in use”现象执行runserver报错提示8000端口被占用或直接崩溃退出。原因上一次运行没关干净或者有其他程序占了8000端口。解决改用其他端口启动即可不必纠结于8000python manage.py runserver 8080如果想彻底解决找到占用进程杀掉。macOS/Linux下用lsof -i :8000Windows下用netstat -ano | findstr 8000然后taskkill对应PID。更要养成一个好习惯用CtrlC停止服务而不是直接关终端窗口否则进程容易残留。6. 从“能跑”到“敢交”上线前的安全加固与验证习惯6.1 把SECRET_KEY和数据库配置从代码里拆出去Django项目用SECRET_KEY做签名泄露它意味着攻击者可以伪造会话Cookie、密码重置链接。我见过有人把整个项目传到公开仓库后SECRET_KEY裸露在settings.py里这是危险的。上线前至少做到两点第一SECRET_KEY从环境变量读取第二DEBUG强制为False并配置ALLOWED_HOSTS。import os SECRET_KEY os.environ.get(DJANGO_SECRET_KEY, dev-only-insecure-key) DEBUG os.environ.get(DJANGO_DEBUG, True) True ALLOWED_HOSTS os.environ.get(DJANGO_ALLOWED_HOSTS, *).split(,)逻辑说明这套写法的逻辑是——本地开发时没设环境变量自动用兜底值不影响日常开发部署时通过环境变量注入真实密钥即使是同一份代码库在不同环境里行为也不同。ALLOWED_HOSTS默认*表示接受任何域名访问生产环境必须显式写成你的域名或IP否则有HTTP Host头攻击风险。6.2 用Django检查命令和本地验证清单上线前跑一遍python manage.py check --deployDjango会列出你还没做到的安全配置项包括SECRET_KEY是否硬编码、DEBUG是否为True、ALLOWED_HOSTS是否为空等。这个检查不能保证部署一定成功但能帮你扫掉90%的基础问题。我给自己定的验证清单是这样的检查项命令/方法通过标准数据表生成python manage.py migrate无错误输出路由可达访问/vote/和/admin/页面正常加载后台登录用createsuperuser账号登录能进入管理界面表单提交投一票并查看数据变化票数1且无403静态资源打开浏览器开发者工具Network面板CSS/JS无404数据库备份python manage.py dumpdata backup.json生成json文件最后聊聊我的习惯每次改模型前先想“这个改动会不会影响已存在的数据”改完立刻makemigrations和migrate代码提交前跑一遍python manage.py check。这套流程让我的项目从“能跑”变成“敢交”——交给导师、交给领导、交给用户都不心虚。如果你刚上手Django建议把这篇提到的代码从头敲一遍不要复制粘贴。敲的过程中你会踩到那些只有动手才能遇到的错那才是真正学会的时刻。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑