3天搞定用python做美食网站保姆级建站教程

3天搞定用python做美食网站保姆级建站教程

改个需求建站公司拖一周,这种憋屈事我见得太多了。很多山东的独立站长朋友,手里有点想法,想做个美食分享站或者本地探店小程序,找外包报价两三万,改个按钮颜色还得排队等排期。其实,用python做美食网站根本没这么难,只要掌握核心逻辑,你自己就能搞定。今天这篇保姆级建站教程,就是专门给想摆脱外包束缚的你准备的,咱们不整虚的,直接上手。

需求分析与技术选型

在动手写代码前,先别急着开编辑器。做网站和做菜一样,得先备菜。很多新手一上来就装库,结果做到一半发现架构不对,全得推翻重来。

做美食网站,核心就三块:展示、交互、数据。 展示是指菜品的图片、名称、做法;交互是指用户评论、收藏、点赞;数据是指这些内容存哪里。

针对独立站长,尤其是咱们山东这边很多做餐饮连锁或美食自媒体的人,我推荐的技术栈是 Flask + SQLite。 为什么不用 Django?Django 功能全但太重,对于个人站长来说,维护成本太高。Flask 轻量灵活,Python 语法简单,加上 SQLite 免安装数据库,环境配置最少,最适合快速验证想法。

另外,考虑到国内服务器部署和备案问题,前端建议直接用 Flask 模板渲染,不要搞前后端分离。前后端分离虽然解耦,但静态资源托管、API 跨域、Nginx 反向代理配置,对于初学者来说是巨大的坑。Flask 模板 + Jinja2 语法,足够应付 90% 的企业官网和小型内容站。

这里要特别提醒一点:域名和服务器。 如果你打算长期运营,建议直接在阿里云或腾讯云购买服务器,并完成 ICP 备案。备案期间(通常 7-20 个工作日)可以用临时域名开发。关于 SSL 证书,不要自己折腾生成证书了,去 Cloudflare 官网看下文档,他们提供免费的 Universal SSL,而且 Cloudflare 的 CDN 对国内访问速度也有优化,配置起来比 Nginx 直接配证书简单多了。

环境准备与依赖安装

工欲善其事,必先利其器。这里以 Windows 10/11 为例,Linux 和 Mac 同理。

  1. 安装 Python:去 python.org 下载最新稳定版(建议 3.9+),安装时务必勾选 "Add Python to PATH",这步忘了后面会抓狂。
  2. 安装 VS Code:这是目前最流行的编辑器,插件生态无敌。
  3. 初始化项目: 打开终端,创建一个文件夹 food_site,进入目录,执行以下命令:
mkdir food_site
cd food_site
python -m venv venv
# Windows激活虚拟环境
venv\Scripts\activate
# Linux/Mac激活虚拟环境
# source venv/bin/activate

激活后,你会看到命令行前面多了 (venv) 标识。接着安装 Flask:

pip install flask

就这一个库,先跑起来再说。等基础功能通了,再按需添加其他库(比如 Flask-SQLAlchemy 处理数据库)。

核心步骤:搭建基础框架

现在我们要搭建一个最简的美食网站骨架。

1. 创建主应用文件

food_site 根目录下新建 app.py

from flask import Flask, render_template, request, redirect, url_forapp = Flask(__name__)# 简单的内存存储,生产环境请换成数据库
dishes = [{"id": 1, "name": "糖醋里脊", "desc": "酸甜可口,外酥里嫩", "img": "images/lichi.jpg"},{"id": 2, "name": "地三鲜", "desc": "东北经典,茄子土豆青椒", "img": "images/disanxian.jpg"}
]@app.route('/')
def index():"""首页:展示所有菜品"""return render_template('index.html', dishes=dishes)@app.route('/dish/<int:dish_id>')
def dish_detail(dish_id):"""详情页:展示单个菜品"""# 查找对应菜品,找不到返回404dish = next((d for d in dishes if d['id'] == dish_id), None)if not dish:return "404 Not Found", 404return render_template('detail.html', dish=dish)if __name__ == '__main__':# debug=True 方便调试,上线前必须改为 Falseapp.run(debug=True, host='0.0.0.0', port=5000)

代码解析

  • @app.route('/'):定义路由,访问根路径时执行 index 函数。
  • render_template:Flask 的模板渲染引擎,它会去找 templates 文件夹下的 HTML 文件。
  • dishes:这里用了个列表模拟数据库,方便新手理解。实际项目中,这里应该从 SQLite 查询。

2. 创建模板文件夹结构

Flask 有严格的目录规范,必须在根目录下创建 templates 文件夹。

templates 下新建 base.html(基础模板,用于复用头尾):

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>{% block title %}美味中国{% endblock %}</title><!-- 引入Bootstrap让页面好看点 --><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="bg-light"><nav class="navbar navbar-expand-lg navbar-dark bg-danger"><div class="container"><a class="navbar-brand" href="/">🍜 美味中国</a><ul class="navbar-nav ms-auto"><li class="nav-item"><a class="nav-link active" href="/">首页</a></li></ul></div></nav><div class="container my-4">{% block content %}{% endblock %}</div><footer class="text-center py-3 bg-dark text-light"><p>Copyright &copy; 2023 山东独立站长</p></footer><script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

接着创建 index.html(首页):

{% extends "base.html" %}{% block title %}首页 - 美味中国{% endblock %}{% block content %}
<h2 class="mb-4">今日推荐</h2>
<div class="row">{% for dish in dishes %}<div class="col-md-4 mb-3"><div class="card h-100 shadow-sm"><!-- 图片占位,实际需上传到static文件夹 --><img src="/static/{{ dish.img }}" class="card-img-top" alt="{{ dish.name }}"><div class="card-body"><h5 class="card-title">{{ dish.name }}</h5><p class="card-text text-muted">{{ dish.desc }}</p><a href="{{ url_for('dish_detail', dish_id=dish.id) }}" class="btn btn-primary">查看详情</a></div></div></div>{% endfor %}
</div>
{% endblock %}

最后创建 detail.html(详情页):

{% extends "base.html" %}{% block title %}{{ dish.name }} - 美味中国{% endblock %}{% block content %}
<div class="card mx-auto" style="max-width: 600px;"><div class="card-body"><h1 class="card-title text-danger">{{ dish.name }}</h1><img src="/static/{{ dish.img }}" class="img-fluid mb-3" alt="{{ dish.name }}"><p class="lead">{{ dish.desc }}</p><hr><h5>做法步骤</h5><ol class="list-group list-group-numbered"><li class="list-group-item">准备食材...</li><li class="list-group-item">切配处理...</li><li class="list-group-item">下锅烹饪...</li></ol><a href="{{ url_for('index') }}" class="btn btn-outline-secondary mt-3">返回首页</a></div>
</div>
{% endblock %}

别忘了在根目录创建 static 文件夹,并在其中创建 images 子文件夹,放入你的菜品图片。Flask 会自动把 static 目录下的文件映射到 /static 路径。

代码配置与数据库持久化

上面的代码用列表存数据,重启服务数据就丢了。真实项目必须用数据库。我们引入 Flask-SQLAlchemy 和 SQLite。

pip install flask-sqlalchemy

修改 app.py,引入 ORM 模型:

from flask import Flask, render_template, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemyapp = Flask(__name__)
# 配置数据库路径,SQLite文件会在项目根目录生成
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///food.db'
db = SQLAlchemy(app)# 定义数据模型,相当于创建表结构
class Dish(db.Model):id = db.Column(db.Integer, primary_key=True)name = db.Column(db.String(100), nullable=False)desc = db.Column(db.String(200))img = db.Column(db.String(200), default='images/default.jpg')steps = db.Column(db.Text) # 存储做法步骤def __init__(self, name, desc, img, steps):self.name = nameself.desc = descself.img = imgself.steps = steps# 初始化数据库并添加测试数据
with app.app_context():db.create_all()if not Dish.query.first():# 插入一条测试数据d = Dish(name="红烧肉", desc="肥而不腻,入口即化", img="images/hongshaorou.jpg",steps="1.焯水去血沫 2.炒糖色 3.小火慢炖90分钟")db.session.add(d)db.session.commit()@app.route('/')
def index():# 从数据库查询所有菜品dishes = Dish.query.order_by(Dish.id.desc()).all()return render_template('index.html', dishes=dishes)@app.route('/dish/<int:dish_id>')
def dish_detail(dish_id):dish = Dish.query.get_or_404(dish_id)return render_template('detail.html', dish=dish)if __name__ == '__main__':app.run(debug=True)

关键点

  • db.create_all():根据模型自动创建表。
  • Dish.query.order_by(...): ORM 查询语法,比手写 SQL 安全且简洁。
  • 注意:每次修改模型结构后,如果数据库已存在,可能需要删除旧的 food.db 文件重新生成,或者使用 Alembic 进行迁移(生产环境建议用 Alembic)。

常见报错与解决方案

新手写 Python Web 项目,80% 的坑都出在下面这几个地方:

  1. ModuleNotFoundError: No module named 'flask'

    • 原因:没激活虚拟环境,或者装到了全局 Python 而不是当前环境。
    • 解决:检查命令行前缀是否有 (venv)。如果没有,重新激活。确认 pip list 里有 Flask。
  2. TemplateNotFound: index.html

    • 原因:文件路径不对。Flask 默认在 app/templates 或项目根目录 templates 找文件。
    • 解决:确保 templates 文件夹和 app.py 在同一层级,且文件名全小写(Linux 区分大小写,Windows 不区分但养成好习惯)。
  3. 500 Internal Server Error

    • 原因:代码里有 Python 异常,但 Flask 只报了 500。
    • 解决:看终端(Terminal)里的红色报错信息。通常是 AttributeError(变量名拼错)或 TypeError(类型不匹配)。比如你在模板里用了 dish.name,但 Python 传过去的是 None
  4. 静态资源不更新

    • 原因:浏览器缓存。
    • 解决:开发时强制刷新(Ctrl+F5)。上线后,可以在文件名加版本号,如 style.v1.css
  5. 数据库锁错误 database is locked

    • 原因:SQLite 不支持高并发写。
    • 解决:个人站长够用。如果并发高,换 PostgreSQL 或 MySQL。

小结与部署建议

到这里,一个具备基本功能的美食网站雏形已经出来了。你用 Python 做这个网站,最大的优势在于迭代速度快。今天想加个“收藏”功能,下午就能上线,不用等外包排期。

关于部署,既然提到了 Cloudflare 文档,这里给一个稳健的上线方案:

  1. 服务器:阿里云/腾讯云轻量应用服务器,选 Ubuntu 22.04。
  2. Web 服务器:Nginx 反向代理 Flask。Flask 自带的开发服务器不适合生产环境。
  3. 进程管理:使用 Gunicorn 运行 Flask 应用。
    pip install gunicorn
    gunicorn -w 4 -b 0.0.0.0:8000 app:app
    
  4. SSL 与 CDN:域名解析到 Cloudflare,开启 Free SSL。Nginx 配置 443 端口指向 Gunicorn。这样既能加密传输,又能利用 Cloudflare 的全球节点加速静态资源。

最后提醒: Python 做网站虽然简单,但安全是底线。

  • 永远不要把 debug=True 留在生产环境。
  • 用户输入的数据(比如评论)一定要过滤,防止 XSS 攻击。
  • 定期备份 food.db 文件。

建站是一场持久战,技术只是工具,内容才是灵魂。你踩过哪些建站的坑?评论区交流。