Python WEB 框架入门

Python WEB 框架入门

主要组件

  1. Web 浏览器
    • 用户使用 Web 浏览器(如 Chrome、Firefox、Safari 等)发送 HTTP 请求。在这个过程中,用户可能输入 URL、点击链接或提交表单等。
  2. Web 服务器
    • Web 服务器(如 Apache、Nginx)接收来自浏览器的 HTTP 请求并作出响应。它负责处理静态资源(如 HTML、CSS、JavaScript 文件、图片等)以及将动态请求转发到 Web 框架应用程序。
  3. Web 框架应用程序
    • Web 框架(如 Flask、Django、FastAPI)处理动态请求。它根据请求的 URL 路由决定调用哪个视图函数。在视图函数中,应用程序的业务逻辑会被执行,比如数据处理、访问数据库等。
  4. 数据库
    • 应用程序在需要时会访问数据库(如 MySQL、PostgreSQL、MongoDB等)以获取或存储数据。通常通过 ORM (对象关系映射) 技术简化数据库操作。
  5. 模板
    • 若响应需要动态 HTML,应用程序会使用模板引擎(如 Jinja2、Django Template)将数据渲染成 HTML 页面,并返回给 Web 服务器,然后再发送给 Web 浏览器。
  6. 静态资源
    • Web 服务器直接提供静态资源(如图片、样式表、JavaScript 文件),用户请求的静态资源可以直接返回,而无需经过应用程序。

流程描述

  1. 用户请求
    • 用户通过 Web 浏览器发起 HTTP 请求,可能请求一个网页或资源。
  2. Web 服务器处理
    • Web 服务器接收请求,根据请求的 URL 进行判断。
    • 如果是静态资源(如 .html.css、图片等),Web 服务器直接返回该资源。
    • 如果是动态内容的请求(如 API 调用或表单提交),Web 服务器将请求转发给 Web 框架应用程序。
  3. Web 框架应用程序处理
    • Web 框架应用程序接收请求,调用相应的视图函数。
    • 视图函数中可能会处理数据逻辑、访问数据库等,并生成需要的动态内容。
  4. 数据库交互
    • 如果需要获取或存储数据,框架应用程序将与数据库进行交互。
  5. 使用模板生成响应
    • 视图函数会将获取到的数据与模板结合,渲染成最终的 HTML 页面。
  6. 返回响应
    • 渲染后的内容通过 Web 框架返回给 Web 服务器,Web 服务器将最终的 HTML 响应发送回 Web 浏览器。
  7. 用户查看
    • Web 浏览器接收到 HTML 页面并进行渲染,用户看到网页的内容。

项目部署

项目结构

project/
│
├── app.py           ← Python 后端
├── templates/
│   └── form.html    ← HTML 表单模板
└── static/
    ├── css/
    │   └── styles.css    ← 静态 CSS 文件
    ├── js/
    │   └── script.js      ← 静态 JavaScript 文件
    └── uploads/           ← 用户头像上传的位置

项目说明

  1. Python后端 (app.py)
    • Flask 是一个轻量级的Python Web框架,用于构建Web应用程序。这个文件包含应用的路由,数据库模型(使用Flask-SQLAlchemy),以及用户数据的处理逻辑。
    • 项目使用 PyMySQL 连接到 MySQL 数据库并通过SQLAlchemy管理数据模型。
    • 提供了一个API,用于接收表单提交的用户信息(包括用户名、密码、性别、爱好、简介和头像),并将这些信息存储在数据库中。
  2. HTML 模板 (templates/)
    • form.html 是一个用户注册表单的HTML模板。它利用 Jinja2 模板引擎来动态呈现内容(例如,表单的反馈信息)。
    • 表单中使用了 fetch API 进行异步提交,使得在不刷新页面的情况下将数据发送到后端。
  3. 静态资源 (static/)
    • CSS 文件夹 (css/):
      • styles.css 文件包含了应用的样式定义,使得前端界面美观和用户友好。
    • JavaScript 文件夹 (js/):
      • script.js 文件包含了用于处理表单提交和与后端通信的JavaScript代码。利用 Fetch API,使得前端能够与后端进行非同步交互,并接收返回的数据。
    • 上传文件夹 (uploads/):
      • 用于存储用户上传的头像文件。

数据库设置

首先确保你已经安装了MySQL数据库

创建数据库

在MySQL中创建一个名为user_db的数据库,并执行如下SQL命令:

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(255) NOT NULL,
    password VARCHAR(255) NOT NULL,
    gender VARCHAR(20),
    hobbies TEXT,
    bio TEXT,
    avatar_path VARCHAR(255)
);

创建app.py

下面是完整的app.py后端代码,包括数据库功能和Fetch API的实现:

from flask import Flask, render_template, request, jsonify
from flask_sqlalchemy import SQLAlchemy
import os
import pymysql  # 导入 PyMySQL

# 使用 PyMySQL 替代 MySQLdb
pymysql.install_as_MySQLdb()

app = Flask(__name__)

# 配置数据库,使用 PyMySQL
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://user:password@localhost/user_db'  # 替换为你的数据库用户名和密码
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)

# 用户模型
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(255), nullable=False)
    password = db.Column(db.String(255), nullable=False)
    gender = db.Column(db.String(20))
    hobbies = db.Column(db.Text)
    bio = db.Column(db.Text)
    avatar_path = db.Column(db.String(255))

# 设置头像上传路径
UPLOAD_FOLDER = 'static/uploads'
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

@app.route('/')
def index():
    return render_template('form.html')

@app.route('/submit', methods=['POST'])
def submit():
    # 获取文本字段
    username = request.form.get('username')
    password = request.form.get('password')
    gender = request.form.get('gender')
    hobbies = request.form.getlist('hobby')  # 多选
    bio = request.form.get('bio')

    # 处理上传头像
    avatar = request.files.get('avatar')
    avatar_path = None
    if avatar and avatar.filename:
        avatar_path = os.path.join(app.config['UPLOAD_FOLDER'], avatar.filename)
        avatar.save(avatar_path)

    # 将数据保存到数据库
    new_user = User(username=username, password=password, gender=gender,
                    hobbies=', '.join(hobbies), bio=bio, avatar_path=avatar_path)
    db.session.add(new_user)
    db.session.commit()

    # 返回 JSON 数据
    result = {
        'username': username,
        'gender': gender,
        'hobbies': hobbies,
        'bio': bio,
        'avatar_saved_to': avatar_path
    }

    return jsonify(result)

if __name__ == '__main__':
    with app.app_context():  # 创建应用上下文
        db.create_all()  # 确保创建数据库和表
    app.run(debug=True)

创建form.html

这是HTML用户注册表单模板。

form.html中,引入静态资源,添加JavaScript部分使用Fetch API来提交表单数据而不是在页面上直接提交表单。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
</head>
<body>
  <div class="form-container">
    <h2>用户注册</h2>
    <form id="userForm" enctype="multipart/form-data">
      <div class="form-group">
        <label for="username">用户姓名</label>
        <input type="text" id="username" name="username" required>
      </div>

      <div class="form-group">
        <label for="password">用户密码</label>
        <input type="password" id="password" name="password" required>
      </div>

      <div class="form-group">
        <label>性别</label>
        <div class="form-group-inline">
          <label><input type="radio" name="gender" value="male" required>男</label>
          <label><input type="radio" name="gender" value="female" required>女</label>
        </div>
      </div>

      <div class="form-group">
        <label>爱好</label>
        <div class="form-group-inline">
          <label><input type="checkbox" name="hobby" value="music">音乐</label>
          <label><input type="checkbox" name="hobby" value="sports">运动</label>
          <label><input type="checkbox" name="hobby" value="reading">阅读</label>
        </div>
      </div>

      <div class="form-group">
        <label for="bio">个人简介</label>
        <textarea name="bio" id="bio" rows="4"></textarea>
      </div>

      <div class="form-group">
        <label for="avatar">上传头像</label>
        <input type="file" id="avatar" name="avatar">
      </div>

      <div class="form-group">
        <button type="submit">提交</button>
      </div>
    </form>
    <div id="result"></div>
  </div>

  <script src="{{ url_for('static', filename='js/script.js') }}"></script>
</body>
</html>

添加静态CSS和JavaScript文件

创建一个static/css/styles.css文件并将你的样式代码放入其中

body {
  font-family: Arial, sans-serif;
  background-color: #f2f2f2;
  padding: 40px;
}

.form-container {
  background-color: white;
  padding: 30px;
  max-width: 400px;
  margin: auto;
  border-radius: 8px;
  box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}

h2 {
  text-align: center;
}

.form-group {
  margin-bottom: 15px;
}

label {
  display: block;
  font-weight: bold;
  margin-bottom: 5px;
}

input[type="text"],
input[type="password"],
input[type="file"],
textarea,
select {
  width: 100%;
  padding: 8px;
  border: 1px solid #ccc;
  border-radius: 4px;
  box-sizing: border-box;
}

.form-group-inline {
  display: flex;
  gap: 10px;
}

.form-group-inline label {
  font-weight: normal;
}

button {
  background-color: #4CAF50;
  color: white;
  padding: 10px 15px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

button:hover {
  background-color: #45a049;
}

.password-strength {
  font-size: 0.9em;
  color: gray;
}

接下来,我们可以创建一个static/js/script.js文件,并将Fetch API的JavaScript代码放入其中:

document.getElementById('userForm').addEventListener('submit', function(event) {
  event.preventDefault(); // 防止默认提交

  const formData = new FormData(this); // 收集表单数据

  fetch('/submit', {
    method: 'POST',
    body: formData
  })
  .then(response => response.json())
  .then(data => {
    document.getElementById('result').innerHTML = `提交成功:<br>用户名:${data.username}<br>性别:${data.gender}<br>爱好:${data.hobbies}<br>简介:${data.bio}<br>头像路径:${data.avatar_saved_to}`;
  })
  .catch(error => {
    console.error('发生错误:', error);
  });
});

启动应用

安装依赖后,确保数据库运行,执行:

python app.py

在浏览器中打开 http://127.0.0.1:5000/,你会看到用户注册表单,填写信息并提交后,数据将通过Fetch API发送到后端,并返回结果。

Python WEB 框架入门
Python WEB 框架入门
Python WEB 框架入门
Python WEB 框架入门

最后可以将前端代码优化一下:

更新form.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>用户注册</title>
  <style>
    body {
      font-family: Arial, sans-serif; /* 设置字体 */
      background-color: #f2f2f2; /* 背景色 */
      padding: 40px; /* 内边距 */
      display: flex; 
      justify-content: center; 
      align-items: center; 
      height: 100vh; /* 垂直居中 */
      margin: 0; /* 去掉默认外边距 */
    }

    .form-container {
      background-color: white; /* 表单背景 */
      padding: 30px; /* 内边距 */
      max-width: 400px; /* 最大宽度 */
      margin: auto; /* 自动外边距以居中 */
      border-radius: 8px; /* 圆角效果 */
      box-shadow: 0 4px 8px rgba(0,0,0,0.1); /* 阴影效果 */
    }

    h2 {
      text-align: center; /* 标题居中 */
      color: #333; /* 标题颜色 */
      margin-bottom: 20px; /* 标题间距 */
    }

    .form-group {
      margin-bottom: 15px; /* 每个表单组之间的下间距 */
    }

    label {
      display: block; /* 块级元素 */
      font-weight: bold; /* 加粗 */
      margin-bottom: 5px; /* 底部间距 */
    }

    input[type="text"],
    input[type="password"],
    input[type="file"],
    textarea,
    select {
      width: 100%; /* 宽度撑满容器 */
      padding: 10px; /* 内边距 */
      border: 1px solid #ccc; /* 边框 */
      border-radius: 4px; /* 圆角 */
      box-sizing: border-box; /* 包含内边距和边框在宽度内 */
      margin-top: 8px; /* 输入框上方间距 */
      font-size: 14px; /* 输入框字体大小 */
    }

    .form-group-inline {
      display: flex; /* 使用弹性布局 */
      gap: 20px; /* 每项之间的间距 */
      flex-wrap: wrap; /* 多行排列 */
    }

    button {
      background-color: #4CAF50; /* 绿色背景 */
      color: white; /* 字体颜色 */
      padding: 10px 15px; /* 内边距 */
      border: none; /* 去掉默认边框 */
      border-radius: 4px; /* 圆角 */
      font-size: 16px; /* 字体大小 */
      cursor: pointer; /* 鼠标悬浮手形 */
      transition: background-color 0.3s; /* 动画过渡 */
      width: 100%; /* 按钮宽度撑满 */
    }

    button:hover {
      background-color: #45a049; /* 悬停时变深绿色 */
    }
  </style>
</head>
<body>
  <div class="form-container">
    <h2>用户注册</h2>
    <form id="userForm" enctype="multipart/form-data">
      <div class="form-group">
        <label for="username">用户姓名</label>
        <input type="text" id="username" name="username" required>
      </div>

      <div class="form-group">
        <label for="password">用户密码</label>
        <input type="password" id="password" name="password" required>
      </div>

      <div class="form-group">
        <label>性别</label>
        <div class="form-group-inline">
          <label><input type="radio" name="gender" value="male" required>男</label>
          <label><input type="radio" name="gender" value="female" required>女</label>
        </div>
      </div>

      <div class="form-group">
        <label>爱好</label>
        <div class="form-group-inline">
          <label><input type="checkbox" name="hobby" value="music">音乐</label>
          <label><input type="checkbox" name="hobby" value="sports">运动</label>
          <label><input type="checkbox" name="hobby" value="reading">阅读</label>
        </div>
      </div>

      <div class="form-group">
        <label for="bio">个人简介</label>
        <textarea name="bio" id="bio" rows="4" required></textarea>
      </div>

      <div class="form-group">
        <label for="avatar">上传头像</label>
        <input type="file" id="avatar" name="avatar">
      </div>

      <div class="form-group">
        <button type="submit">提交</button>
      </div>
    </form>
    <div id="result"></div>
  </div>
  <script src="{{ url_for('static', filename='js/script.js') }}"></script>
</body>
</html>
Python WEB 框架入门

web 服务器构建

目前这个项目没有使用专门的Web服务器(如Nginx或Apache)来部署这个Flask应用。目前使用的是Flask自带的开发服务器,这是适合开发和测试的,但不适合生产环境。

目前推荐WSGI(Web Server Gateway Interface)服务器来运行Flask应用,如Gunicorn或uWSGI,并将其与Nginx或Apache等作为反向代理服务器结合使用,以提高性能和安全性。

安装Gunicorn

pip install gunicorn

安装 Nginx

我这里使用的 MAC,可以使用 Homebrew 来安装 Nginx。打开终端并输入以下命令:

brew install nginx
brew services start nginx

您可以在浏览器中访问 http://localhost:8080 来查看 Nginx 是否成功运行。默认情况下,Nginx 将监听 8080 端口。

配置 Nginx

Nginx 的配置文件位于 /opt/homebrew/etc/nginx/nginx.conf。您可以使用任何文本编辑器打开该文件进行修改:

vim /opt/homebrew/etc/nginx/nginx.conf

在配置文件中,您需要添加一个 server 块来配置 Nginx 以转发请求到您的 Flask 应用。假设您的 Flask 应用使用 Gunicorn 运行在 localhost:8000,那么您可以这样配置:

server {
    listen 8888;
    server_name localhost;

    location / {
        proxy_pass http://127.0.0.1:8000;  # 修改为 Gunicorn 监听的地址和端口
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

启动 Gunicorn

在另一个终端窗口中,启动您的 Flask 应用。例如,如果您的应用在 app.py 中,可以这样启动:

gunicorn -w 4 -b 127.0.0.1:8000 app:app

在这里,-w 4 表示启动4个工作进程,-b 用于指定绑定的地址和端口。

检查并重启 Nginx

在修改 Nginx 配置后,您需要重启 Nginx,以使更改生效。您可以用以下命令重启 Nginx:

nginx -t
brew services restart nginx

测试

在浏览器中访问 http://localhost:8888,Nginx 将转发请求到的Flask 应用运行在 Gunicorn 上。

Python WEB 框架入门

动静分离体现

Flask项目通过定义静态目录和动态路由来有效区分和管理动静态数据:

动态资源请求

动态数据的处理主要由Flask路由来管理。在你项目的app.py中,通过定义不同的路由来处理用户请求,返回动态生成的数据。例如:

路由处理对根路径的GET请求,并返回渲染的HTML模板form.html

@app.route('/')
def index():
    return render_template('form.html')  # 返回动态HTML内容

处理表单提交的路由/submit,这里的内容依赖于用户提交的数据,在submit()中,返回的数据(JSON格式)基于用户输入的数据,体现了动态处理。

@app.route('/submit', methods=['POST'])
def submit():
    username = request.form.get('username')
    # 其他处理...
    return jsonify(result)  # 返回动态生成的JSON响应

静态资源管理

对于静态资源(如CSS、JavaScript和图像文件),Flask通过static/目录管理这些文件,这些文件在服务器上是固定的并可以直接被客户端获取:

<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
<script src="{{ url_for('static', filename='js/script.js') }}"></script>

处理静态和动态资源的分离

  • 静态内容:不需要进行服务器端计算处理的内容(如固定的CSS、JavaScript和图片文件)直接服务于用户请求。这些资源通过Nginx或Apache等Web服务器提供,加快加载速度和减少服务器负担。
  • 动态内容:依赖用户输入或数据库查询的内容,将数据逻辑封装在Flask的视图函数中,根据请求的不同返回相应的内容。

发布者:LJH,转发请注明出处:https://www.ljh.cool/43062.html

Like (0)
LJHLJH
Previous 2天前
Next 2023年4月20日 上午1:46

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注