WEB开发: 全栈工程师起步 - Python Flask +SQLite的管理系统实现

一、前言

罗马不是一天建成的。

 每个全栈工程师都是从HELLO WORLD 起步的。

之前我们分别用NODE.JS 、ASP.NET Core 这两个框架实现过基于WebServer的全栈工程师入门教程。

今天我们用更简单的来实现: Python。

我们将用Python来实现一个学生管理应用,它包括Web服务器+管理前端+后端Api+数据库,并满足一个管理应用所具有的基本的增删查功能。由此来熟悉Phthon的webServer (Flask )应用。

二、流程和技术栈

先来看下我们设想的应用流程

然后根据这个来设定一下我们的技术栈:

  1. 前端:HTML + JS + CSS
    前端开发利用HTML来构建网页的骨架和内容结构,CSS用于定义网页的样式和布局,如字体、颜色、空间等,确保网页在不同设备上的视觉效果一致。JavaScript则负责网页的动态交互功能,如响应用户输入、动画效果和与服务器的通信,使得网页变得互动性强,提升用户体验。

  2. 服务器:Python Flask
    Flask是一个轻量级的Python Web框架,适合构建小型到中型的Web应用。它简洁、易于上手,并且高度可扩展。Flask允许开发者定义路由、处理HTTP请求、与数据库交互,并能够快速搭建RESTful API服务,广泛用于开发Web服务和微服务。Flask的灵活性使得开发者可以根据需求选择需要的功能和扩展。

  3. 数据库:SQLite
    SQLite是一种轻量级的嵌入式关系型数据库管理系统,适用于桌面和移动设备应用。它将数据存储在一个单一的文件中,不需要独立的数据库服务器,安装和配置非常简单。SQLite支持SQL标准,可以高效地存储、查询、更新数据,适合用在低并发、数据量较小的项目中,常用于原型开发、小型应用和嵌入式系统。

三、文件结构

所以 首先你需要在自己的电脑上安装PYTHON。默认都有了。

然后需要 pip install  sqlite3。 安装这个数据库引擎。

一切齐全,准备动手,动手前先确定一下这个项目的目录文件结构:

目录结构

/student-grade-management
  ├── app.py                  # Flask应用的主程序
  ├── students.db             # SQLite数据库文件
  ├── /templates              # 存放HTML模板文件的文件夹
  |    └── index.html         # 主页面的HTML文件
  ├── /static                 # 存放静态资源(如CSS, JS, 图片等)的文件夹
       ├── style.css          # 样式文件(CSS)
       └── script.js          # 前端脚本(JavaScript)

这个目录结构是一个典型的 Flask 项目的结构,适用于一个简单的学生成绩管理系统。下面我将逐一解释每个文件和文件夹的作用:

详细解释

1. app.py
  • 作用:这是你的 Flask Web 应用的主程序。Flask 是一个轻量级的 Python Web 框架,用于快速开发 Web 应用。
  • 功能:在这个文件中,我们会定义所有的路由(URLs)、视图函数(处理请求的函数)和一些与数据库交互的代码。
    • 例如:
      • /   路由显示学生成绩列表。
      • /add   路由处理添加学生成绩。
      • /delete/<id>   路由处理删除学生成绩。
      • /search   路由处理按姓名查询学生成绩。
    • 该文件还负责启动 Flask Web 服务器(通常使用 app.run())。
2. students.db
  • 作用:这是 SQLite 数据库文件,存储系统中的所有数据。
  • 功能:SQLite 是一个轻量级的数据库,它会将数据保存在本地文件中。这个数据库文件包含一个表(比如 students),存储学生的姓名和成绩。
    • 该数据库可以使用 Python 的 sqlite3 库进行操作。
    • 例如,系统会在此数据库中进行以下操作:
      • 插入新学生成绩。
      • 查询学生成绩。
      • 删除学生成绩。

        请注意这个db文件最开始需要用脚本生成,脚本中设定了各个字段、表名,见后i面的文件介绍。
3. /templates
  • 作用:这个文件夹存放 Flask 应用的 HTML 模板文件,Flask 会使用 Jinja2 模板引擎来渲染这些 HTML 文件。

  • 功能

    • Flask 会使用模板文件来动态生成页面内容。
    • 在我们的项目中,index.html 作为主页面模板,显示学生成绩列表,并提供添加、删除和查询功能。
    • Jinja2 语法使得我们可以在 HTML 中插入 Python 变量、执行条件语句、循环等操作。
    • 例如,学生的姓名和成绩列表会从数据库中获取,Flask 会将这些数据传递到模板中,然后通过模板渲染显示在页面上。

    例如:

    <table>
        <thead>
            <tr>
                <th>姓名</th>
                <th>成绩</th>
            </tr>
        </thead>
        <tbody>
            {% for student in students %}
            <tr>
                <td>{{ student.name }}</td>
                <td>{{ student.grade }}</td>
            </tr>
            {% endfor %}
        </tbody>
    </table>
    
4. /static
  • 作用static 文件夹用来存放 Web 应用中不会变化的静态资源文件,如 CSS、JavaScript、图片等。

  • 功能:这些静态文件是客户端直接访问的文件,不需要通过 Flask 后端处理。Flask 会自动处理 static 文件夹中的文件并提供服务。

    • style.css:存放样式表文件(CSS),用于控制页面的外观和布局。你可以在 index.html 中引用它,定义页面的字体、颜色、布局等样式。
    • script.js:存放 JavaScript 文件,用于处理客户端的交互逻辑。例如,处理添加、删除、查询学生成绩的事件,或者发送 AJAX 请求来与 Flask 后端进行交互。

    例如:

    <link rel="stylesheet" href="/static/style.css">
    <script src="/static/script.js"></script>
    

典型流程

  1. 用户在浏览器中访问 Flask 应用时,Flask 会根据请求路由选择适当的视图函数。
  2. 视图函数可以与数据库交互,获取或修改数据。
  3. 数据传递到模板中,模板使用 Jinja2 引擎动态生成 HTML 页面并返回给浏览器。
  4. 浏览器根据返回的 HTML 内容渲染页面,并加载 static 文件夹中的 CSS 和 JavaScript 资源。

四、源码

以下是各个部分的源码:

dbMake.py (这个是一个脚本,用来生成数据库,运行这个脚本可以在根目录下生成一个数据库文件 students.db)

import sqlite3

# 连接数据库(如果数据库文件不存在,会自动创建)
conn = sqlite3.connect('students.db')

# 创建一个cursor对象
cursor = conn.cursor()

# 创建学生成绩表
cursor.execute('''
CREATE TABLE IF NOT EXISTS students (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    grade INTEGER NOT NULL
)
''')

# 提交并关闭
conn.commit()
conn.close()

app.py

from flask import Flask, render_template, request, jsonify
import sqlite3

app = Flask(__name__)

# 获取数据库连接
def get_db_connection():
    conn = sqlite3.connect('students.db')
    conn.row_factory = sqlite3.Row  # 返回字典类型的行
    return conn

# 首页,显示学生成绩列表
@app.route('/')
def index():
    conn = get_db_connection()
    students = conn.execute('SELECT * FROM students').fetchall()
    conn.close()
    return render_template('index.html', students=students)

# 添加学生成绩
@app.route('/add', methods=['POST'])
def add_student():
    name = request.form['name']
    grade = request.form['grade']
    conn = get_db_connection()
    conn.execute('INSERT INTO students (name, grade) VALUES (?, ?)', (name, grade))
    conn.commit()
    conn.close()
    return jsonify({"status": "success"})

# 查询学生成绩
@app.route('/search', methods=['GET'])
def search_student():
    name = request.args.get('name', '')
    conn = get_db_connection()
    students = conn.execute('SELECT * FROM students WHERE name LIKE ?', ('%' + name + '%',)).fetchall()
    conn.close()
    return render_template('index.html', students=students)

# 删除学生成绩
@app.route('/delete/<int:id>', methods=['GET'])
def delete_student(id):
    conn = get_db_connection()
    conn.execute('DELETE FROM students WHERE id = ?', (id,))
    conn.commit()
    conn.close()
    return jsonify({"status": "success"})

if __name__ == '__main__':
    app.run(debug=True)

script.js

document.getElementById('add-student-form').addEventListener('submit', function (event) {
    event.preventDefault();

    const name = document.getElementById('name').value;
    const grade = document.getElementById('grade').value;

    fetch('/add', {
        method: 'POST',
        body: new URLSearchParams({
            'name': name,
            'grade': grade
        })
    })
        .then(response => response.json())
        .then(data => {
            if (data.status === 'success') {
                alert('学生成绩已添加!');
                window.location.reload(); // 刷新页面
            }
        });
});

// 删除学生成绩
function deleteStudent(id) {
    if (confirm('确定要删除这个成绩吗?')) {
        fetch(`/delete/${id}`)
            .then(response => response.json())
            .then(data => {
                if (data.status === 'success') {
                    alert('学生成绩已删除!');
                    window.location.reload(); // 刷新页面
                }
            });
    }
}

// 查询学生成绩
document.getElementById('search-form').addEventListener('submit', function (event) {
    event.preventDefault();

    const name = document.getElementById('search-name').value;

    fetch(`/search?name=${name}`)
        .then(response => response.text())
        .then(data => {
            document.body.innerHTML = data; // 更新页面内容
        });
});

style.css

body {
    font-family: Arial, sans-serif;
    margin: 20px;
    background-color: #f9f9f9;
}

h1 {
    text-align: center;
}

table {
    width: 50%;
    margin: 0 auto;
    border-collapse: collapse;
}

th, td {
    padding: 10px;
    text-align: center;
}

form {
    margin-top: 20px;
    text-align: center;
}

input, button {
    padding: 10px;
    margin: 5px;
}

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>学生成绩管理系统</title>
    <link rel="stylesheet" href="/static/style.css">
</head>
<body>
    <h1>学生成绩管理系统</h1>

    <h2>查询学生成绩</h2>
    <form id="search-form">
        <label for="search-name">姓名: </label><br>
        <input type="text" id="search-name" name="name"><br><br>
        <button type="submit">查询</button>
    </form>

    <h2>学生成绩列表</h2>
    <table border="1">
        <thead>
            <tr>
                <th>姓名</th>
                <th>成绩</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody id="students-list">
            {% for student in students %}
            <tr>
                <td>{{ student.name }}</td>
                <td>{{ student.grade }}</td>
                <td>
                    <button onclick="deleteStudent({{ student.id }})">删除</button>
                </td>
            </tr>
            {% endfor %}
        </tbody>
    </table>

    <h2>添加学生成绩</h2>
    <form id="add-student-form">
        <label for="name">姓名: </label><br>
        <input type="text" id="name" name="name"><br><br>
        <label for="grade">成绩: </label><br>
        <input type="number" id="grade" name="grade"><br><br>
        <button type="submit">添加</button>
    </form>

    <script src="/static/script.js"></script>
</body>
</html>

准备完毕,命令行切入根目录,执行 python app.py 启动应用

显示 服务器启动了  端口是5000  使用 http://127.0.0.1:5000 可以访问这个应用:

 

万丈高楼平地起,这个还有一些bug,可以自己修复。祝你好运!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/939396.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【我的 PWN 学习手札】IO_FILE 之 stdin任意地址写

我们知道&#xff0c;stdin会往“缓冲区”先读入数据&#xff0c;如果我们劫持这个所谓“缓冲区”到其他地址呢&#xff1f;是否可以读入数据到任意地址&#xff1f;答案是肯定的。 注意&#xff01;代码中的“-------”分隔&#xff0c;是为了区分一条调用链上不同代码片段&am…

从 Dify 到 Rill-Flow:大模型应用平台的进化之路

1. 基于 dify 的大模型应用平台构建 近些年&#xff0c;大语言模型领域的高速发展&#xff0c;涌现出了众多优秀的产品&#xff0c;能够解决很多实际的业务场景&#xff0c;大幅提升工作效率。各公司都纷纷搭建起了自己的大模型应用平台&#xff0c;来统一管理各种大语言模型&…

37. Three.js案例-绘制部分球体

37. Three.js案例-绘制部分球体 实现效果 知识点 WebGLRenderer WebGLRenderer 是Three.js中的一个渲染器类&#xff0c;用于将3D场景渲染到网页上。 构造器 WebGLRenderer( parameters : Object ) 参数类型描述parametersObject渲染器的配置参数&#xff0c;可选。 常用…

基于 SSM 框架 Vue 电脑测评系统:赋能电脑品质鉴定

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;作为一个一般的用户都开始注重与自己的信息展示平台&#xff0c;实现基于SSM框架的电脑测评系统在技术上已成熟。本文介绍了基于SSM框架的电脑测评系统的开发全过程。通过分析用户对于基于SSM框架的电脑测评系统的…

二七(vue2-03)、生命周期四个阶段及八个钩子、工程化开发和脚手架、组件注册、拆分组件

1. 生命周期 1.1 生命周期四个阶段 <!-- Vue生命周期&#xff1a;一个Vue实例从 创建 到 销毁 的整个过程。生命周期四个阶段&#xff1a;① 创建 ② 挂载 ③ 更新 ④ 销毁1.创建阶段&#xff1a;创建响应式数据2.挂载阶段&#xff1a;渲染模板3.更新阶段&#xff1a;修改…

Group FLUX - Beta Sprint Essay4

文章目录 I. SCRUMAchievements from yesterday’s stand-up meeting to the presentKey Features Demonstrated in Beta PM ReportBurnup mapRunning image of our current program I. SCRUM Achievements from yesterday’s stand-up meeting to the present Zhong Haoyan: …

c++-----------------类和对象(中)

1.类的默认成员函数 默认的成员函数就是用户没有显示实现&#xff0c;编译器会自动生成的成员函数称为默认的成员函数。一个类我们在不写的情况下编译器会自动生成以下6个默认的成员函数&#xff0c;这6个最重要的是前面4个&#xff0c;后面的了解一下就可以了。默认成员函数很…

Qt中的异步相关类

Qt中的异步相关类 今天在学习别人的项目时&#xff0c;看到别人包含了QFuture类&#xff0c;我没有见过&#xff0c;于是记录一下。 直接在AI助手中搜索QFuture,得到的时Qt中异步相关的类。于是直接查询一下Qt异步中相关的类。 在Qt中&#xff0c;异步编程是一个重要的概念&…

WPF DataTemplate 数据模板

DataTemplate 顾名思义&#xff0c;数据模板&#xff0c;在 wpf 中使用非常频繁。 它一般用在带有 DataTemplate 依赖属性的控件中&#xff0c;如 ContentControl、集合控件 ListBox、ItemsControl 、TabControls 等。 1. 非集合控件中使用 <UserControl.Resources>&l…

爬虫案例学习6

获取淘宝商品数据2024-12-18 参考学习&#xff1a; 大佬博客 视频教程 通过搜索发现&#xff0c;数据是通过发送请求过来的&#xff0c;不是静态存在源代码的 所以我们需要请求这个接口获取数据&#xff1a;比如标题&#xff0c;价格&#xff0c;图片等信息 https://h5api.m…

Linux学习——9_Ubuntu Linux操作系统

Ubuntu Linux操作系统 Ubuntu简介 Ubuntu Linux是由南非人马克沙特尔沃思(Mark Shuttleworth)创办的基于Debian Linux的操作系统&#xff0c;于2004年10月公布 Ubuntu是一个以桌面应用为主的Linux发行版操作系统 Ubuntu拥有庞大的社区力量&#xff0c;用户可以方便地从社区…

springboot449教学资源共享平台(论文+源码)_kaic

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统教学资源共享平台信息管理难度大&#xff0c;容错率低&am…

各向同性重建(3D荧光图像)

文章目录 一、基本知识1.1、各向同性&#xff08;isotropic&#xff09; 各向异性&#xff08;anisotropic&#xff09;1.2、像素尺寸 像素间距 像素分辨率1.3、点扩散函数&#xff08;PSF&#xff09;1.3.1、高斯函数 二维高斯PSF1.3.2、二维高斯PSF&#xff1a;代码生成 …

计算机毕业设计论文指导

计算机毕业设计论文指导 计算机毕业设计辅导一站式&#xff01;太香了&#x1f4aa; [赞R][赞R][赞R]嗨喽&#xff01;计算机专业的宝子们&#xff01; 计算机毕设辅导专业靠谱的他来了&#xff01;&#xff01; 是不是还在为选题程序不会做而感到苦难&#xff1f; 论文没思路赶…

【Windows版】opencv 和opencv_contrib配置

一、参考资料 &#xff08;四十一&#xff09;CMakeVSopencv/opencv_contrib 环境配置 从源码安装&#xff2f;penCV&#xff0c;使用python windowsvscodeopencv源码安装配置 二、关键步骤 1. opencv与opencv_contrib版本对齐 下载 opencv 下载 opencv_contrib opencv…

如何制作搞笑配音视频?操作方法

在数字娱乐盛行的今天&#xff0c;搞笑配音视频凭借其独特的幽默感和创意&#xff0c;在网络上赢得了大量观众的喜爱。如果你也想尝试制作一部让人捧腹的搞笑配音视频&#xff0c;那么请跟随以下步骤&#xff0c;从撰写搞笑文案到视频配音剪辑&#xff0c;一步步打造你的作品。…

C++手动实现一个HashMap

1.HashMap原理 参考我的博客&#xff1a;https://blog.csdn.net/Revendell/article/details/110009858 开链法&#xff1a;STL的hashtable便是采用开链法解决冲突。这种做法是在每一个表格元素中维护一个list&#xff1a;散列函数为我们分配某一个list&#xff0c;然后我们在…

threejs+vue3+js旋转词云

title: threejs date: 2024-12-11 09:50:41 tags: threes Threejs 双行可展示旋转词云显示。 一、简单案例——旋转球体 以下代码使用vue3jsthreejs技术站进行的搭建&#xff0c;其中包含了场景创建、相机创建、渲染器创建、物体材创建等相关流程&#xff0c;构建了一个简单…

RocketMQ源码分析(四) 延迟消息源码分析

0.前文 RocketMQ源码分析&#xff08;三&#xff09; 消费者 RocketMQ源码分析&#xff08;二&#xff09; 生产者 RocketMQ源码分析&#xff08;一&#xff09;broker启动&remoting抽象 1. 概述 RocketMQ的延迟消息是指消息发送到Broker后&#xff0c;不会立即被消费者…

嵌入式单片机中对应GPIO外设详解实现

一、GPIO外设详解 大家可以看到,函数库开发的时候外设的使用流程都是一样的,接下来就讲解一下细节。 l定义一个外设的结构体变量 变量命名规则 PPP_InitTypeDef PPP_InitStructure; 每个外设都有对应的结构体,结构体的定义一般都是存放在每个外设的头文件内,比如GPIO外…