尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Flask入门教程:从零搭建你的第一个Python Web应用

Flask入门教程:从零搭建你的第一个Python Web应用 还记得我刚开始学Python时满脑子都是“能不能用Python直接做个网页”。翻了很多资料绕来绕去最后是Flask把我带进了Web开发的门。你如果也有类似想法或者已经有Python基础、想快速搭一个能跑起来的小网站或者接口服务这篇Flask入门心得就是给你写的。Flask是一个轻量级的Python Web框架核心只有路由和模板如果你只想做个博客、API服务、后台管理系统或者单纯想搞懂“浏览器输入网址之后Python到底执行了什么”Flask是最低门槛的选择。本篇文章不吹概念直接带你从环境安装、第一个程序、模板、表单、数据库到工程化结构一路跑通顺带把我在实际操练中踩过的坑也一并说清楚。1. 为什么要从Flask开始而不是先去啃Django很多新手来问我后端框架第一句就是“学Django还是Flask”。我的回答通常是如果目标是快速做出东西、理解Web运行原理先选Flask。这不是说Django不好而是两者解决的学习痛点不一样。Django是一个“全家桶”式框架自带Admin后台、ORM、表单、认证体系功能齐全但概念多。你用Django的第一个小时可能卡在“settings配置和迁移命令”上而不是在写页面。Flask完全不同它只做最核心的事接受HTTP请求调用你写的Python函数返回HTML字符串。其他功能通过安装不同扩展来补扩展用哪个装哪个代码量很小心智负担低。用生活化的例子来说Flask像乐高积木先给你一小盒基础件想搭什么按需拼Django更像整装模型零件齐全但得按说明书组装。对于初学者、喜欢研究底层逻辑和需要快速迭代原型的人Flask这种“随时裸写”的方式特别舒服。从工程角度来说Flask的应用场景覆盖得很广。很多小型微服务、数据展示平台、个人博客甚至企业内部工具系统都在用它。最近两三年FastAPI热度很高但在上手难易度、模板渲染、生态成熟度上Flask依然是很多人的首选。Flask的扩展非常丰富比如flask-sqlalchemy操作数据库、flask-wtf处理表单、flask-restful写API学会了核心部分后面基本靠组合扩展就行。我见过不少同学直接从高版本框架或者复杂的大型项目开始结果被各种概念劝退。反过来用Flask写三个小项目之后再回头看Django、FastAPI理解成本会低非常多因为你已经知道“框架到底在帮你解决哪些问题”。2. 环境准备与第一个Flask应用2.1 安装Python并选择版本Flask是Python的第三方库前提是机器上得有个能用的Python环境。现在官方推荐直接装Python 3.10以上版本大部分Flask功能都能完美支持。如果你用的是Windows去Python官网下载安装包几乎每个版本的安装界面都有“Add Python to PATH”这个选项一定记得勾上。这一步不勾后面终端输入python会提示找不到命令非常常见。装好之后打开命令行输入python --version能显示版本号就说明安装成功。如果你电脑里存在多个Python版本比如系统自带3.8又装了3.11建议优先用Python自带的py启动器来处理比如py -3.11这样每个版本可以独立调用互不干扰。在Linux或macOS上则可以用python3来区分系统Python和手动安装版本。我之前踩过一个很低级的坑第一次安装没勾PATH后面pip都调不起来又重装了一遍。现在写教程我都会把“勾选PATH”这件事放在第一优先级提醒。2.2 安装Flask并解决下载慢的问题Python环境就绪后下一步就是安装Flask。使用pip命令是最直接的方式pip install flask如果你的下载速度很慢或者经常超时建议使用国内镜像源pip install flask -i https://pypi.tuna.tsinghua.edu.cn/simple安装完成后建议你用下面的命令确认一下版本方便后续排查问题python -m flask --version这条命令不仅会显示Flask版本还会显示当前Python版本和系统信息是我排查环境问题时最常用的命令之一。这里多提一句千万不要在系统全局环境里装一堆包尤其是如果你除了学习Flask还做爬虫、数据分析很容易造成依赖冲突。后面我们马上讲到虚拟环境这才是解决环境混乱的正确方案。2.3 虚拟环境每个项目一套专属环境虚拟环境可以理解为给当前项目建一个独立的Python“小仓库”里面安装的库和全局环境隔离不同项目互不影响。我见过很多新手图省事所有库都装全局最后为了修依赖冲突浪费大量时间非常不值得。用Python自带的venv模块创建虚拟环境命令非常简单。在项目根目录执行python -m venv venvWindows激活venv\Scripts\activateLinux/macOS激活source venv/bin/activate激活后命令行前面会出现(venv)字样这就说明你已经在虚拟环境里面了。这时候再pip install的包只会装进当前项目不会污染全局。退出虚拟环境直接执行deactivate。很多新手问Pycharm和VSCode怎么配置Python环境。其实底层都是指向这个venv目录下的python解释器。VSCode里面按CtrlShiftP输入“Python: Select Interpreter”选择当前项目的venv就行PyCharm则是File - Settings - Project - Python Interpreter里添加。配置一次后面运行和调试就不用管了。2.4 写第一个Flask程序虚拟环境配置完成我们写一个最简单的Flask应用。新建一个app.py文件输入下面代码from flask import Flask app Flask(__name__) app.route(/) def index(): return 你好Flask! if __name__ __main__: app.run(debugTrue)在终端执行python app.py看到类似“Running on http://127.0.0.1:5000”的提示后浏览器打开这个地址页面上出现“你好Flask!”就说明你的第一个Flask应用已经跑起来了。这里解释一下代码背后的逻辑Flask(__name__)是创建Flask实例参数__name__用来告诉Flask去哪找模板和静态文件这个参数虽然看起来简单但写错会影响资源加载。app.route(/)是路由装饰器意思是用户访问网站根路径时执行下面的index函数。if __name__ __main__保证只有直接执行这个脚本时才启动开发服务器被作为模块导入时不会重复启动。调试时建议把debugTrue加上改代码后服务器能自动重载省去手动重启的功夫。但部署到生产环境时一定记得改成debugFalse否则会暴露详细错误信息造成安全隐患。3. 路由、模板与静态资源3.1 动态路由与请求方法第2章的/路由是最简单的实际开发中会经常遇到需要根据不同类型的URL返回不同内容的场景。Flask支持动态路由例如app.route(/post/int:post_id) def show_post(post_id): return f文章编号{post_id}访问/post/123post_id就会自动取到123。注意这里的int:post_id做了类型转换如果传字符串就会匹配失败并返回404这是一种很方便的参数校验方式。除了int还有float和path等转换器其中path比较特殊它允许URL中包含斜杠。如果你想让同一个URL同时支持GET和POST请求就要显式声明app.route(/submit, methods[GET, POST]) def submit(): if request.method POST: return 这是POST请求 return 这是GET请求新手最容易漏掉的地方就是methods参数不写的话默认只支持GET前端发POST过来会报“Method Not Allowed”。排查时多看这个提示基本能猜出原因。3.2 用Jinja2模板渲染页面路由直接返回字符串适合接口或者测试页。真要写一个用户访问的网页更合理的做法是使用模板。Flask内置了Jinja2模板引擎它允许你在HTML文件里用类似Python的语法输出变量、写循环和判断。先在项目根目录创建templates文件夹新建一个hello.html!DOCTYPE html html head titleFlask示例页面/title /head body h1你好{{ name }}/h1 {% for item in items %} p{{ item }}/p {% endfor %} /body /html然后再改app.pyfrom flask import Flask, render_template app Flask(__name__) app.route(/hello/name) def hello(name): items [番茄蛋饭, 红烧肉, 清蒸鱼] return render_template(hello.html, namename, itemsitems)这里必须注意两点templates文件夹必须和app.py在同一目录下除非你通过template_folder参数指定了其他位置否则Flask不会去别的地方找模板。render_template的第二个参数开始都是在往模板里传变量。模板里的{{ name }}会被自动替换成对应的值{% for %}这种带百分号的语法是语句标签用于循环和条件判断。模板最大的价值在于“模板继承”。你可以写一个base.html作为公共框架包含头部、导航栏、底部版权信息然后子页面用{% extends base.html %}继承只需重写{% block content %}内容块即可。这样全站页面的导航和样式改一处就全变了不需要每个页面都复制一遍HTML。3.3 静态文件使用网页不可能只有HTMLCSS、JavaScript、图片都属于静态文件。Flask约定把这些文件统一放在static目录。假设项目根目录下建了static/style.css在模板中这样引用link relstylesheet href{{ url_for(static, filenamestyle.css) }}用url_for生成静态文件的URL是一个好习惯。这样即使以后你改了文件目录层级模板里的引用也会自动更新不用手动改几十处路径。我第一次写Flask项目就是嫌麻烦硬编码了/static/style.css后来项目搬家文件路径变了一次修改起来非常痛苦。另外新手容易把静态文件误放到templates里面。Flask虽然也能访问但会污染模板目录结构增加缓存和路由出错的概率。规则很简单能被浏览器直接访问的资源文件放static需要通过后端传数据渲染的页面文件放templates。4. 表单提交与数据库读写4.1 处理用户提交的数据网页开发离不开表单。用户输入内容提交到后端后端处理完再返回结果这几乎是所有Web应用的通用流程。我们做一个最简单的留言板先写一个显示表单的模板再写后端路由接收数据。templates/msg.html!DOCTYPE html html head meta charsetutf-8 title留言板/title /head body form methodpost input typetext namecontent placeholder请输入留言 input typesubmit value提交 /form ul {% for msg in messages %} li{{ msg }}/li {% endfor %} /ul /body /html后端对应逻辑from flask import Flask, render_template, request app Flask(__name__) messages [] app.route(/msg, methods[GET, POST]) def msg(): if request.method POST: content request.form.get(content) if content: messages.append(content) return render_template(msg.html, messagesmessages)request.form是接收表单POST数据的标准方式。request.args则用于接收URL查询参数比如/list?page2这种。初学者最容易混淆这两个对象记住一句话POST表单数据用formGET参数用args。这里我给代码留了一个小细节如果用户提交空内容我就不会追加到列表里。这些小校验在真实项目中非常重要不要嫌繁琐任何用户输入都是不可信的后端必须做一次基本判断。4.2 安装SQLAlchemy并配置数据库上面留言板实现虽然能用但数据都存在列表里服务器一重启就全部丢失。实际项目中我们需要把数据持久化到数据库。Flask生态中最常用的ORM是flask-sqlalchemy它把数据库表封装成Python类操作记录就像操作对象一样简单不需要手写SQL。安装pip install flask-sqlalchemy在app.py中配置SQLite数据库from flask import Flask from flask_sqlalchemy import SQLAlchemy app Flask(__name__) app.config[SQLALCHEMY_DATABASE_URI] sqlite:///msg.db app.config[SQLALCHEMY_TRACK_MODIFICATIONS] False db SQLAlchemy(app) class Message(db.Model): id db.Column(db.Integer, primary_keyTrue) content db.Column(db.String(500), nullableFalse)SQLite是一个文件型数据库sqlite:///msg.db会在项目目录下生成一个msg.db文件适合学习和小型项目。如果你以后要切换成MySQL只需要把数据库连接字符串改成对应的格式模型代码几乎不用动这就是ORM带来的便利。使用db.create_all()创建表这句代码只在第一次运行时执行即可。可以在交互命令行里运行python然后输入from app import db, Message db.create_all()关闭终端即可。我看到很多人每次启动程序都执行db.create_all()虽然不会出错但生产环境并不推荐表结构复杂后应该有专门的迁移工具比如Flask-Migrate来管理。4.3 把留言板改造成数据库版本有了数据库模型我们改造留言板代码from flask import Flask, render_template, request from flask_sqlalchemy import SQLAlchemy app Flask(__name__) app.config[SQLALCHEMY_DATABASE_URI] sqlite:///msg.db app.config[SQLALCHEMY_TRACK_MODIFICATIONS] False db SQLAlchemy(app) class Message(db.Model): id db.Column(db.Integer, primary_keyTrue) content db.Column(db.String(500), nullableFalse) app.route(/msg, methods[GET, POST]) def msg(): if request.method POST: content request.form.get(content) if content: new_msg Message(contentcontent) db.session.add(new_msg) db.session.commit() messages Message.query.all() return render_template(msg.html, messages[m.content for m in messages])这段代码里有两个关键操作db.session.add(new_msg)和db.session.commit()是写入数据库的标准流程。add表示把记录加入会话commit才是真正提交到数据库。忘记commit是新手最常犯的错误因为代码不报错但数据就是没进去。Message.query.all()是查询所有记录Flask-SQLAlchemy提供了非常友好的查询接口包括get()按主键查、filter_by()按条件查、order_by()排序等。这样改造后即使重启应用留言数据依然存在。整个学习过程中从“列表存数据”到“数据库存数据”是一次非常重要的升级理解了这一层后续几乎所有Web应用都能往这个框架上套。5. 工程目录规划与部署5.1 从单文件走向多文件工程很多新手写着写着就把所有路由、数据库模型、配置全堆在一个app.py里面。一两百行还好到了五百行以上维护起来就非常痛苦。我建议从一开始就养成规范工程结构的习惯。一个建议的项目结构myblog/ ├── app/ │ ├── __init__.py │ ├── views.py │ ├── models.py │ └── templates/ │ └── static/ ├── config.py ├── run.py ├── requirements.txt └── venv/run.py是入口文件负责创建应用并启动from app import create_app app create_app() if __name__ __main__: app.run(debugTrue)app/__init__.py里定义create_app工厂函数把所有初始化和蓝图注册放在一起from flask import Flask from flask_sqlalchemy import SQLAlchemy db SQLAlchemy() def create_app(): app Flask(__name__) app.config.from_object(config.Config) db.init_app(app) from .views import main app.register_blueprint(main) return appviews.py里面用蓝图定义路由。蓝图是Flask里用于模块化路由的机制简单说就是“带名分的路由集合”它能让你把不同功能拆分到不同文件。比如博客的路由写在blog.py用户模块写在user.py最后统一注册到应用上。用蓝图前我也觉得单文件还行但项目一旦加了后台管理、API接口各自为政的文件会让开发效率高很多。5.2 本地运行与线上部署开发时app.run()起的开发服务器够用但生产环境一般不会直接用因为开发服务器的并发能力和稳定性都不足以应对真实需求。常见做法是使用WSGI服务器比如gunicornLinux/macOS或者waitressWindowspip install gunicorn gunicorn -w 4 -b 0.0.0.0:8000 run:app-w 4表示启动4个worker进程-b指定监听地址和端口run:app指的是模块run里的app实例。把0.0.0.0作为监听地址服务器才能对外提供服务只写127.0.0.1就只能本机访问。部署方式很多比较现代化的是Docker。一个简单的Dockerfile大概长这样FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple COPY . . CMD [gunicorn, -w, 4, -b, 0.0.0.0:5000, run:app]有了这个Dockerfile在项目根目录执行docker build -t flask-demo . docker run -d -p 5000:5000 flask-demo就能把Flask应用打包成一个镜像在任意装了Docker的服务器上运行。Docker最大的好处是解决了环境一致性问题我在本地跑得好好的代码扔到服务器上一堆依赖报错的情况非常常见用容器化之后基本没再出现。5.3 依赖清单与版本锁定无论部署到哪里规范记录项目依赖都很有必要。执行pip freeze requirements.txt会把当前虚拟环境的所有包和版本写入文件。换一台机器后只需pip install -r requirements.txt就能还原环境依赖。这里我习惯推荐多装一个pip-tools来管理依赖但入门阶段pip freeze完全够用。如果发现装了一堆不相关的包生成的清单很臃肿也可以手动编辑只保留确实用到的包。6. 常见问题排查与避坑指南学习Flask过程中有些问题属于几乎每个新手都会遇到的。我整理了一份速查表方便你直接对照排查。现象可能原因解决办法运行flask run报错未激活虚拟环境或flask未安装检查终端前缀是否带(venv)执行pip install flask页面提示404 Not Found路由路径拼写错误或动态参数类型不匹配检查app.route里的路径与浏览器访问的路径完全一致提示“Method Not Allowed”路由没有声明POST方法在app.route中加入methods[GET,POST]模板无法找到templates文件夹名称或位置错误确认模板在项目根目录下的templates文件夹内浏览器打开中文乱码HTML缺少字符集声明在head中加入meta charsetutf-8port 5000 is in use端口被其他程序占用换端口如app.run(port8000)修改代码后页面不变化没开启debug模式设置为debugTrue或手动重启服务器除了表格里的问题还有几个我实际踩过的坑值得展开说一下。第一个坑写完中文返回给前端变乱码。这是因为Flask在返回JSON时默认对中文进行了ASCII编码。解决方案是在创建应用时设置配置项app.config[JSON_AS_ASCII] False这样jsonify返回的中文就能正常显示。第二个坑装了库但Python一直说找不到。绝大部分原因是虚拟环境没激活或者VSCode选择的解释器不是当前项目的venv。装库时命令行前缀得有(venv)VSCode里要确认右下角解释器指向正确。还有一种情况是Windows下用PowerShell执行venv\Scripts\activate遇到执行权限限制可以临时改用venv\Scripts\activate.bat或者调整PowerShell执行策略。第三个坑PyCharm社区版没有Flask模板。很多教程会推荐用PyCharm专业版的Flask工程模板但社区版没有这个选项。解决方案很简单创建一个普通Python项目手动新建app.py然后配置好解释器就行。模板本质上就是帮你建目录自己动手建一次印象反而更深刻。第四个坑路由里函数名重复。Flask用endpoint作为视图函数唯一标识如果你两个函数都叫index()哪怕路径不同启动时也会报View function mapping is overwriting错误。所以给视图函数起名字时别偷懒尽量语义化和差异化。第五个坑用python -m flask run启动时找不到入口模块。默认Flask会找app.py或wsgi.py如果你的入口文件叫别的名字启动前需要设置环境变量Windowsset FLASK_APPrun.pyLinux/macOSexport FLASK_APPrun.py然后再执行flask run即可。个人经验是如果只是本地开发直接python run.py更省心不用操心环境变量。在最后分享一个我的个人习惯如果你已经顺利跑通了上面所有步骤说明你基本掌握了Flask的核心开发流程。我个人在实际操作中还有一个习惯就是每当新学一个框架都会尝试在最短时间内做一个很小的完整项目比如“个人记账本”或者“代办清单”。因为单独的教程章节看完很容易忘但把路由、模板、表单、数据库合起来做一个真实可用的东西这些知识才真正长在脑子里了。在学习Debug那段时间我还依赖过一个很笨但有效的排查方法在路由函数里临时加print()把拿到的表单值、数据库查询结果打到终端里。别看这方法土但解决了很多排查瓶颈。等你熟悉了Flask提供的调试工具栏或者装上flask-debugtoolbar看SQL查询和变量信息再逐步过渡到专业的调试方式就行。最后提醒一句Flask的官方文档质量很高遇到不熟悉的功能先查官方文档和扩展的文档不要一搜就去看二手教程。很多报错实际在官方文档里都有明确说明只是我们经常懒得逐行看而已。希望这篇Flask入门整理能帮你省掉我当年走过的弯路接下来就直接动手吧把第一个网页跑起来比看十篇教程都有用。
返回列表