ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Django实战教程:创建项目、URL路由与第一个视图

Django实战教程:创建项目、URL路由与第一个视图 1. 开始前的取舍Python版本、虚拟环境和pip源的确定很多同学第一次接触 Django是在搜“Python 网站开发”的时候。装好 Python执行了pip install django然后照着某个帖子敲完django-admin startproject mysite再python manage.py runserver浏览器弹出那个火箭发射一样的大写“It worked”页面成就感满满。但接下来呢官方文档看到第二页不少人就在urls.py和views.py之间迷路了——到底该在哪个文件里写“Hello World”写了之后又要去哪里才能看到就成了第一道坎。这篇文章按我带新同事上手的顺序来写从装 Python 和 Django、建项目建应用、写第一个视图、配模板和静态文件到开发阶段最容易踩的几个坑最后再指一下往模型、后台和部署走的方向。你跟着操作二十分钟内就能在浏览器里看到自己亲手写的响应。如果你刚接触 Django或者已经装好但卡在视图这一步直接照着往下走就行。1.1 选 Python 版本别一味追求最新安装 Django 之前先确认 Python。我理解你肯定想装最新版但在正式项目里我劝你冷静一点——第三方库的兼容性往往是滞后的Django 5.0 的某个新特性很惊艳可很多常用扩展可能还只支持到 Python 3.11。你本地练习无所谓可一旦涉及部署环境、数据库驱动、图片处理这类依赖版本选错会浪费很多时间。我平时给新人的建议很简单用途推荐 Python推荐 Django本地练习 / 快速上手Python 3.10 或 3.11Django 4.2 LTS新项目长期维护Python 3.11 或 3.12Django 5.0老项目维护跟随项目要求跟随 requirements.txtWindows 下安装 Python 时记得在安装向导里勾选“Add Python to PATH”这一步漏了后面在命令行里敲python会提示找不到命令。macOS 和 Linux 一般自带 Python 3但版本可能偏老我建议用python3 --version先看一眼如果低于 3.8还是去官网装一个新的更省心。1.2 虚拟环境不要直接往全局装我知道很多新手图省事直接pip install django把包装到全局当时确实快但坑在后面项目 A 用 Django 3.2项目 B 用 5.0全局环境里同时只能存在一个版本两个项目总有一个跑不起来。所以从第一天开始就用虚拟环境这是性价比最高的习惯。Python 自带的venv就够用不用额外装 virtualenv# Windows python -m venv venv venv\Scripts\activate # macOS / Linux python3 -m venv venv source venv/bin/activate激活成功与否看命令行前面有没有出现(venv)标识。Windows PowerShell 里第一次激活可能会报“禁止运行脚本”这时用venv\Scripts\Activate.ps1不行的话可以改用venv\Scripts\activate.bat或者把 PowerShell 的执行策略放开我记得是运行Set-ExecutionPolicy -ExecutionPolicy RemoteSigned选 Y 就行。这个属于 Windows 权限机制不是 Django 的问题但几乎所有 Windows 新手都会撞上。虚拟环境激活后再安装 Djangopip install django如果安装速度很慢建议用国内镜像加速清华源是我用得最稳的pip install django -i https://pypi.tuna.tsinghua.edu.cn/simple这个操作只是把 pip 下载源换成更快的镜像没有任何额外影响后面装其他库也可以沿用同一个参数。1.3 验证安装结果装完后打开命令行先确认自己还在虚拟环境里然后执行python -m django --version如果打印出版本号比如4.2.16说明核心环境已经就绪。如果提示No module named django八成是你退出过虚拟环境或者当前终端窗口不是激活状态。还有一种情况是django-admin命令找不到这在 Windows 上比较常见原因多半是 Python 的 Scripts 目录没进 PATH。我的建议是少依赖django-admin多使用python -m django这种调用方式它对环境的要求更低报错信息也更明确。到这一步环境就绪了。接下来说说怎么把项目和应用建出来这里有一个新手最容易混淆的概念问题。2. 创建项目与应用一次搞懂 startproject 和 startapp 的分工我第一次教别人 Django 时发现“项目”和“应用”这两个词就是第一道门槛。很多人把startproject建出来的东西当成整个网站把startapp建出来的东西当成网站的一部分然后在命令行里来回试。其实它们的分工用一个盖楼的比喻就能说清楚。2.1 project 和 app一个比喻说明白项目是站点的骨架应用是站点里的功能模块。startproject相当于打地基、搭框架它给你一套完整的配置文件和一个可运行的空站点startapp则相当于给某一个房间做精装修它生成的是具体业务代码的目录结构。同一个项目里可以放多个应用用户模块、博客模块、订单模块它们之间通过 URL 路由串起来。实际操作时先建项目再进到项目目录里建应用django-admin startproject myblog cd myblog python manage.py startapp blog注意startapp前面用的是python manage.py不是django-admin。因为应用是依附于某个项目的必须在这个项目自己的管理命令里创建。如果你看到CommandError: blog conflicts with the name of an existing Python module说明当前目录不对或者模块名和已存在的文件撞了换个应用名字就好。2.2 目录结构哪些文件要动哪些不用动创建完成后整个目录是这样的myblog/ ├── manage.py ├── myblog/ │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ ├── wsgi.py │ └── asgi.py └── blog/ ├── migrations/ │ └── __init__.py ├── __init__.py ├── admin.py ├── apps.py ├── models.py ├── tests.py └── views.py新手阶段你只需要关心四个文件manage.py是命令入口以后所有python manage.py xxx都靠它myblog/settings.py是整个站点的配置中心myblog/urls.py是总路由表blog/views.py是视图函数存放处我们马上要改的就是它。wsgi.py和asgi.py是部署时用的入口现在不用管。migrations目录以后同步数据库时会用到先让它空着就行。2.3 注册应用这一步漏了后面全是问题建完应用之后有个非常容易被忽略的步骤把应用注册进settings.py。打开myblog/settings.py找到INSTALLED_APPS这个列表默认长这样INSTALLED_APPS [ django.contrib.admin, django.contrib.auth, django.contrib.contenttypes, django.contrib.sessions, django.contrib.messages, django.contrib.staticfiles, ]在列表最后加上一行INSTALLED_APPS [ # ... blog, ]不注册会怎样后果很隐蔽你后面建的模板可能找不到数据库迁移命令检测不到这个应用Django 完全不知道它的存在。很多新手在 templates 目录都建好了页面却一直 404 或者 TemplateDoesNotExist回头检查才发现应用根本没注册。我习惯在写完startapp之后立刻注册免得后面排查。到这里项目和应用都建好了接下来就是本篇的核心让第一个视图跑起来。3. 第一个视图如何跑通URL路由到视图函数的请求链路“视图”这个词听起来有点玄其实它就是一段普通 Python 函数。它的职责很简单接收一个网络请求返回一个响应。任何函数只要做到这两件事在 Django 里就能当视图用。3.1 视图函数最简写法打开blog/views.py把里面的内容改成from django.http import HttpResponse def index(request): return HttpResponse(Hello, Django! 这是我的第一个视图。)这里request是 Django 帮你封装好的请求对象里面装着浏览器发来的各种信息比如路径、参数、请求头、用户是否登录等。你现在不需要读懂它只要知道它是视图函数的第一个参数就行。HttpResponse是一个响应对象构造它的第一个参数是响应正文开发服务器会把这段文字作为 HTML 返回给浏览器。保存文件但先别着急运行——还差最后一步得让 Django 知道什么地址对应这个视图函数。3.2 在 urls.py 里建立路由打开myblog/urls.py默认内容是这样的from django.contrib import admin from django.urls import path urlpatterns [ path(admin/, admin.site.urls), ]path(admin/, admin.site.urls)表示访问http://127.0.0.1:8000/admin/时交给 Django 自带的 admin 站点去处理。我们要做的是再加一条规则把网站首页交给刚才写的index视图from django.contrib import admin from django.urls import path from blog import views urlpatterns [ path(admin/, admin.site.urls), path(, views.index), ]path(, views.index)这一行是整个流程的关键第一个参数是访问路径空字符串代表站点首页第二个参数是被调用的视图函数。注意这里传的是函数名views.index不是views.index()不加括号因为 Django 会在请求到达时帮你调用它并自动传入request参数。如果想让视图接收地址里的动态参数写法也很直观path(article/int:pk/, views.article_detail)对应视图函数def article_detail(request, pk): return HttpResponse(f这篇文章的 ID 是 {pk})int:pk的意思是这个位置必须是一个整数Django 会把它解析出来作为参数传给视图。后面学到模型查询时你会经常用到这个写法。新手阶段先记住这个套路就行。现在保存所有文件在项目根目录运行python manage.py runserver浏览器打开http://127.0.0.1:8000/如果能看到“Hello, Django! 这是我的第一个视图。”恭喜你第一个视图已经跑通了。3.3 这条链路里藏着 Django 的 MTV 模式跑通之后顺手解释一个概念很多教程都会反复强调“Django 是 MTV 模式”网上也有不少帖子在问 MTV 到底有什么用。其实从刚才这条请求链路里就能看出来M 是 Model负责和数据库打交道对应以后要写的models.pyT 是 Template负责页面展示对应以后要建的templates目录V 是 View负责业务逻辑对应这个视图函数。一次完整的请求流程是这样的用户输入 URLurls.py匹配路由调起视图函数视图函数如果需要数据就通过 Model 从数据库取拿到数据后交给 Template 渲染成 HTML最后作为响应返回给浏览器。刚才这个index视图是最简链路没有 Model 参与也没有 Template 参与展示效果就特别直观V 自己搞定了一切。以后你把 Model 和 Template 加进来无非是在这条链路上做扩展。这个模式的好处是各个部分职责清晰改页面样式不动业务逻辑换数据库不影响模板渲染。你现在不需要背只要知道“URL 匹配 → 视图处理 → 响应返回”这条主链路就够了后面所有内容都挂在它上面。4. 让视图输出更像样模板渲染与静态文件处理的常见坑第一个视图跑通后下一步自然是把页面做得像个真正的网页。如果每次都用HttpResponse拼接大段 HTML 字符串代码会很快变成一团乱麻。Django 的解决办法是模板把 HTML 单独放到文件里视图只需要往里面填充数据。4.1 从 HttpResponse 到 render先在blog目录下新建一个templates/blog/目录然后在里面新建index.html。注意目录层级我见过太多人把模板直接放到blog/templates/下面结果 Django 报TemplateDoesNotExist。这里多建一层blog目录是有原因的Django 会在所有已注册应用各自的templates目录里找同名模板如果两个应用都有index.htmlDjango 会随机找到其中一个导致张冠李戴。多包一层应用名目录相当于给模板加上命名空间彻底避免冲突。templates/blog/index.html内容!DOCTYPE html html langzh-hans head meta charsetUTF-8 title{{ title }}/title /head body h1{{ content }}/h1 /body /html然后把视图改成from django.shortcuts import render def index(request): context { title: 第一个 Django 页面, content: Hello Django! 这是模板渲染出来的。 } return render(request, blog/index.html, context)render(request, blog/index.html, context)有三个参数request必须有它是上下文来源模板路径相对于templates目录context是传给模板的字典模板里的{{ title }}会被替换成字典里title对应的值。刷新页面你会看到标题和正文都变了但这次内容来自模板文件而不是视图里的字符串。这里想说一下为什么要走模板这条“弯路”当页面结构变复杂、需要在页面里循环显示多条数据时模板的{% for %}、{% if %}标签能让代码可读性高很多而且前端工程师可以直接改模板文件不用碰 Python 代码。视图和页面分离是 Django 从一开始就设计好的协作方式。4.2 静态文件为什么 img 标签显示不出来模板渲染会了之后很多人的下一个问题就是图片、CSS、JS 这些静态文件到底放哪在 VSCode 里写img srclogo.png浏览器却一片空白这种情况我见过太多次了。Django 的规则是静态文件要放在应用下的static目录里然后在模板中通过{% static %}标签引用。我在项目里习惯这样组织blog/ ├── static/ │ └── blog/ │ └── logo.png └── templates/ └── blog/ └── index.html模板里引用图片{% load static %} img src{% static blog/logo.png %} altlogo注意第一行必须写{% load static %}否则{% static %}标签不会生效。{% static blog/logo.png %}会生成一个指向静态文件的完整 URL之后无论项目放在哪个子路径下图片都能正确加载。前提条件有两个settings.py里有STATIC_URL static/以及DEBUG True。开发阶段这两项都是默认满足的。如果你照着做了图片还是显示不出来排查顺序我总结为三步第一步确认文件真实存在于static/blog/下注意大小写和扩展名第二步确认模板顶部写了{% load static %}第三步强制刷新浏览器CtrlF5因为浏览器缓存经常让旧页面死灰复燃。部署阶段还需要用collectstatic把各应用的静态文件收集到统一目录再交给 Nginx 这类服务器处理这个先按下不表等真的到了上线那天再学也来得及。我先在这里提醒一句别在还没跑通本地开发的时候就折腾 Nginx 静态文件那是一条深不见底的岔路。5. 运行调试时容易踩的五个坑第一个视图跑通之后你会开始尝试各种修改这时会陆续遇到一些典型的报错。我把这几个高频坑按出现频率排一下你照着排查基本都能解决。5.1 runserver 起不来端口被占用python manage.py runserver启动时如果提示Error: That port is already in use.说明 8000 端口被别的进程占了。可能是之前有一个没关掉的后台实例也可能是其他软件占了端口。最快的方法是换一个端口启动python manage.py runserver 8080启动之后浏览器访问http://127.0.0.1:8080/就行。如果想彻底查清是谁占用了端口Windows 下用netstat -ano | findstr 8000Linux/macOS 用lsof -i :8000但日常开发里换个端口更快。5.2 局域网访问报 DisallowedHost如果你想让手机或者局域网里的另一台电脑访问你的开发服务器会先启动python manage.py runserver 0.0.0.0:8000然后在另一台设备上输入http://你的局域网IP:8000。这时很可能看到Bad Request (400)页面日志里写着DisallowedHost。原因是 Django 出于安全考虑默认只允许请求头里的 Host 是localhost或127.0.0.1。开发阶段可以直接放开ALLOWED_HOSTS [*]*表示允许任意域名访问开发时方便上线前一定要改成具体的域名。如果你不想放开所有就填局域网 IP比如ALLOWED_HOSTS [192.168.1.10]。这个报错不是代码写错了是 Django 故意的知道这点就不会慌。5.3 中文乱码和时区问题Django 默认语言是英文时区是 UTC。国内项目一般会在settings.py里改成LANGUAGE_CODE zh-hans TIME_ZONE Asia/Shanghai USE_TZ Truezh-hans是简体中文的语言代码Asia/Shanghai是东八区。USE_TZ True是一个容易绕晕的概念开启后Django 在数据库里存的时间统一为 UTC模板渲染时自动转成你设置的时区。这样做的优势是如果你的用户分布在不同时区存储统一时间就不会混乱。代价是初学者经常发现“我明明存了 12 点怎么数据库里是 4 点”这其实就是 UTC 和东八区的 8 小时差值。新手阶段的建议是别给自己增加复杂度先把LANGUAGE_CODE和TIME_ZONE配好时间功能用到时再深入理解USE_TZ。如果只是本地练习、不需要多时区支持把USE_TZ False也能让存取时间更符合直觉。两种方式都能用关键是别一半按这个一半按那个前后不一致才是真正的坑。5.4 数据库相关报错忘了迁移当你第一次尝试访问/admin/后台或者以后用了自定义模型页面报no such table: xxx时原因多半是数据库表还没建。Django 内置了很多表比如用户表、会话表、权限表第一次使用前必须先执行python manage.py migrate这条命令会根据 Django 内置的迁移文件把初始的表结构建好。如果你自己写了模型还要先执行一次python manage.py makemigrations然后再执行migrate。我用一个比喻帮你记makemigrations是根据模型写一份“数据库要改成什么样”的变更说明书migrate才是真正把这份说明书应用到底层数据库。只改models.py不执行迁移命令数据库不会自动变化这是新手非常容易踩的坑。5.5 页面还是旧的自动重载与浏览器缓存runserver默认开了自动重载你保存 Python 文件后它会自动重启。但如果改了模板文件页面上却一直是旧内容优先考虑浏览器缓存按 CtrlF5 强制刷新。另一个常见情况是模板目录名写错Django 认的是templates你如果建成了template或者把 HTML 放错应用目录报错信息里会明确写TemplateDoesNotExist后面跟着它尝试查找的所有路径。看到这个报错不要慌顺着报错列出的路径一个个核对一般很快能定位。这些坑都不是什么高深问题但它们会反复出现。我的经验是遇到报错先看命令行窗口里最后几行日志Django 的报错信息已经非常友好了大多数情况下它会直接告诉你“哪个文件、哪一行、什么原因”。别一上来就整段复制去搜先自己读一遍很多问题当场就能看出来。6. 从视图走向项目的下一站模型、查询与管理后台跑通了视图你就已经掌握了 Django 最核心的一条主链路请求进来、路由匹配、视图处理、响应返回。但一个真正的网站还需要数据这时就要进入 Django 的 M 了。很多人在这个环节第一次感受到 Django 的“香”——一切数据库操作都可以用 Python 完成不用写一句 SQL。6.1 用 ORM 操作数据库先建一个 Post 模型打开blog/models.py写入from django.db import models class Post(models.Model): title models.CharField(max_length100) content models.TextField() created_at models.DateTimeField(auto_now_addTrue)CharField对应数据库里的字符串max_length100是最大长度TextField对应大文本DateTimeField对应时间。auto_now_addTrue表示新建记录时自动填入当前时间之后不再修改。然后在项目根目录运行python manage.py makemigrations blog python manage.py migratemakemigrations blog会为blog应用生成迁移文件migrate把它应用到数据库。这时去数据库里看会多出一张blog_post表字段和你定义的模型一一对应。整个过程完全没有 SQL这就是 Django ORM 的作用用 Python 对象的方式操作数据库自动翻译成对应的 SQL。对新手来说上手门槛低了很多。6.2 在视图里查询和删除对象有了模型和数据接下来就是在视图里查询了。在views.py里写一个列表页from django.shortcuts import render from .models import Post def post_list(request): posts Post.objects.all() return render(request, blog/post_list.html, {posts: posts})Post.objects.all()返回所有文章这是一个查询集QuerySet可以在模板里用{% for %}循环遍历。查询单个对象用Post.objects.get(pk1)按条件过滤用Post.objects.filter(title__containsDjango)。删除是另一个常见操作而且删除比查询更容易造成不可逆影响。两种典型写法# 删除单个对象 post Post.objects.get(pk1) post.delete() # 批量删除 Post.objects.filter(title__contains测试).delete()get().delete()会先取到对象再删除filter().delete()直接在查询集上执行批量删除它会删除所有满足条件的记录。注意filter().delete()是不可逆的我在本地练习时手滑删过一整张表的数据所以现在的习惯是生产项目里用is_deleted字段做软删除而不是物理删除。新手阶段你至少要知道有软删除这个方案免得以后项目上线后为一次误操作懊恼很久。6.3 管理后台不用写页面也能管理数据Django 自带一个后台管理系统这是很多人第一次接触 Django 就被震撼到的功能。在blog/admin.py里注册模型from django.contrib import admin from .models import Post admin.site.register(Post)然后创建管理员账号python manage.py createsuperuser按提示输入用户名、邮箱和密码。之后启动服务器访问http://127.0.0.1:8000/admin/用刚才的账号登录你就能在浏览器里看到 Post 列表可以增删改查不需要写一行前端代码。这一步的成就感非常直观适合作为熟悉 Django 的第二个里程碑。我第一次看到后台那会儿第一反应是“居然白送一套管理系统”后来用多了才发现它还能自定义字段、设置搜索框、定制过滤条件。但那是后话你先把默认功能用明白就够吃一阵了。6.4 下一步往哪走第一个视图跑通、后台也能管理数据之后你的 Django 地基已经打牢了。接下来要学的方向我建议按这个顺序推进先学模板继承把你那个简单的 index.html 拆成 base.html 加子模板顺便引入一个 CSS 框架把页面做得像一个真正的站点再学 Django 表单和 POST 请求实现用户提交数据然后学带参数的 URL 和视图慢慢过渡到类视图Class-Based View之后可以学 Django REST Framework 写接口最后才考虑部署。部署这块多说一句开发时用的runserver只适合调试上生产必须换 WSGI 服务器。Windows 服务器上常见的组合是 waitress 加 nginxLinux 上则是 gunicorn 加 nginx。你现在不用急着装但要知道这个方向真到了上线那天这些都是有现成答案的问题按官方文档一步步来就行比你现在硬啃要轻松得多。最后说点我的体会。我最早学 Django 时在“项目”和“应用”这两个抽象概念上绕了很久总觉得没彻底搞懂就不敢往下写。现在回头看最快的学习方式应该是先把runserver跑起来、把第一个视图改掉哪怕它只返回一行文字也要亲手完成一次从浏览器地址栏输入网址到页面出现自己写的文本的完整闭环。很多概念不需要提前理解靠踩坑再回头补充记忆反而更深。如果你照着本文操作中途卡在某个报错上先看控制台最后一行日志大多数情况下 Django 已经把原因说得很明白了。第一个视图跑通之后你其实已经打通了这条请求链路的主干后面的模型、模板、接口都是在它上面做加法。
返回列表