flask实现简易图书管理系统

news2024/11/18 22:46:18

项目结构

技术选型

flask 做后端, 提供数据和渲染html
暂时没有提供mysql, 后续会更新操作mysql和样式美化的版本

起一个flask服务

flask是python的一个web框架, 下面演示如何提供http接口, 并返回json数据

main.py

# flask创建http接口
from flask import Flask, request, jsonify,render_template
# 支持flask跨域
from flask_cors import CORS 
# 创建flask服务
app = Flask(__name__)
CORS(app, resources=r'/*')  # 注册CORS, "/*" 允许访问域名所有api  

# 首页
@app.route('/',methods=['get'])
def index():
    # 自动在templates里找对应名称的文件
    return jsonify({"msg":"hello"})
 
if __name__ == "__main__":
    # 运行web服务
    app.run(host='0.0.0.0', port=10086)
此时打开终端, 运行

python main.py
打开浏览器, 输入 http://localhost:10086/

渲染模板

flask可以渲染html文件(自动往项目根目录的templates里找), 并往里面填数据

main.py

# flask创建http接口
from flask import Flask, request, jsonify,render_template
# 支持flask跨域
from flask_cors import CORS 
# 创建flask服务
app = Flask(__name__)
CORS(app, resources=r'/*')  # 注册CORS, "/*" 允许访问域名所有api  

# 首页
@app.route('/',methods=['get'])
def index():
    # 自动在templates里找对应名称的文件
    return render_template('index.html',msg="hello world")
 
if __name__ == "__main__":
    # 运行web服务
    app.run(host='0.0.0.0', port=10086)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    {{msg}}
</body>
</html>

浏览器

用对象数组来存放图书数据

main.py

通过模板渲染传递books到html里
# flask创建http接口
from flask import Flask, request, jsonify,render_template
# 支持flask跨域
from flask_cors import CORS 
# 创建flask服务
app = Flask(__name__)
CORS(app, resources=r'/*')  # 注册CORS, "/*" 允许访问域名所有api 
 
# 暂时代替数据库
books = [
    {
        "id":'1',
        "name":"hello world",
        "author":"迭名",
        "desc": "程序员入门第一本书",
        "price": 11.99
    },
    {
        "id":'2',
        "name":"0基础学it",
        "author":"xx程序员",
        "desc": "某培训机构精心出品教程",
        "price": 99.98
    },
]

# 首页
@app.route('/',methods=['get'])
def index():
    # 自动在templates里找对应名称的文件
    return render_template('index.html',books=books)
 
if __name__ == "__main__":
    # 运行web服务
    app.run(host='0.0.0.0', port=10086)

index.html

html接收flask后端传来的数据, 渲染到table里
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<!-- 加样式,居中 -->
<style>
    * {
        margin: 0 auto;
    }
</style>

<body>
    <br>
    <table border="1">
        <thead>
            <tr>
                <th>书名</th>
                <th>作者</th>
                <th>描述</th>
                <th>价格</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            {% for book in books %} {# 遍历 books 变量 #}
            <tr id={{book.id}}>
                <th>{{book.name}}</th>
                <th>{{book.author}}</th>
                <th>{{book.desc}}</th>
                <th>{{book.price}}</th>
                <th>
                    <button id={{book.id}}>删除</button>
                    <a href='http://localhost:10086/uptbook?id={{book.id}}'>修改</a>
                </th>
            </tr>
            {% endfor %} {# 使用 endfor 标签结束 for 语句 #}
        </tbody>
    </table>
    <br>
</body>

</html>

查看效果

添加图书

使用a标签请求flask后端, flask后端返回html模板, 实现跳转添加页面(add.html)
这里add.html是在book下, 这是因为如果还有别的服务(比如用户的crud), 可以通过不同文件夹区分模块

添加两个接口, 我们的id就用book对象在books数组里的下标(索引/序号), 添加就直接append添加到books数组的末尾
# 跳转添加页面
@app.route('/addbook',methods=['get'])
def addbook_html():
    # 自动在templates里找对应名称的文件
    return render_template('book/add.html')

# 添加
@app.route('/addbook',methods=['post'])
def addbook(): 
    # 获取json数据
    book = request.get_json() 
    book['id']= str(len(book)-1) 
    books.append(book)
    return jsonify({"books":books})

main.py

# flask创建http接口
from flask import Flask, request, jsonify,render_template
# 支持flask跨域
from flask_cors import CORS 
# 创建flask服务
app = Flask(__name__)
CORS(app, resources=r'/*')  # 注册CORS, "/*" 允许访问域名所有api 
 
# 暂时代替数据库
books = [
    {
        "id":'1',
        "name":"hello world",
        "author":"迭名",
        "desc": "程序员入门第一本书",
        "price": 11.99
    },
    {
        "id":'2',
        "name":"0基础学it",
        "author":"xx程序员",
        "desc": "某培训机构精心出品教程",
        "price": 99.98
    },
]

# 首页
@app.route('/',methods=['get'])
def index():
    # 自动在templates里找对应名称的文件
    return render_template('index.html',books=books)
 
# 跳转添加页面
@app.route('/addbook',methods=['get'])
def addbook_html():
    # 自动在templates里找对应名称的文件
    return render_template('book/add.html')

# 添加
@app.route('/addbook',methods=['post'])
def addbook(): 
    # 获取json数据
    book = request.get_json() 
    # 用数组下标表示id
    book['id']= str(len(book)-1) 
    # 添加到books末尾
    books.append(book)
    return jsonify({"books":books})
 
if __name__ == "__main__":
    # 运行web服务
    app.run(host='0.0.0.0', port=10086)

index.html

我们使用axios(js的一个库)来发送http请求
<!-- 引入axios发送请求给后端 -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
发送请求前, 通过input框的value获取数据, 然后axios发送post请求, 并传递一个json对象给后端
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <form id="form">
        <lable>书名</lable>
        <input type="text" name="book-name" id="book-name">
        <label>作者</label>
        <input type="text" name="book-author" id="book-author">
        <label>描述</label>
        <input type="text" name="book-desc" id="book-desc">
        <label>价格</label>
        <input type="text" name="book-price" id="book-price">
        <button type="submit">提交</button>
    </form>
    <!-- 引入axios发送请求给后端 -->
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script>
        const addform = document.querySelector("#form")
        const bookName = document.querySelector("#book-name")
        const bookDesc = document.querySelector("#book-desc")
        const bookAuthor = document.querySelector("#book-author")
        const bookPrice = document.querySelector("#book-price")
        addform.addEventListener("submit", function (e) {
            e.preventDefault();
            // console.log(bookName.value);
            // 发送请求给后端
            axios.post('http://localhost:10086/addbook',
                // 传递json数据给后端
                {
                    name: bookName.value,
                    author: bookAuthor.value,
                    desc: bookDesc.value,
                    price: bookPrice.value
                })
                // axios请求完成后
                .then((res) => {
                    // 后端处理完请求,axios拿到的结果
                    console.log(res);
                    alert('添加成功')
                    // 跳转首页
                    window.location.href = 'http://localhost:10086/'
                })
        })
    </script>
</body>

</html>

查看效果

删除图书

我们通过axios发送delete请求给后端, 同时传递id, 后端遍历books, 找到对应id的元素下标, 然后删除

main.py

# flask创建http接口
from flask import Flask, request, jsonify,render_template
# 支持flask跨域
from flask_cors import CORS 
# 创建flask服务
app = Flask(__name__)
CORS(app, resources=r'/*')  # 注册CORS, "/*" 允许访问域名所有api 
 
# 暂时代替数据库
books = [
    {
        "id":'1',
        "name":"hello world",
        "author":"迭名",
        "desc": "程序员入门第一本书",
        "price": 11.99
    },
    {
        "id":'2',
        "name":"0基础学it",
        "author":"xx程序员",
        "desc": "某培训机构精心出品教程",
        "price": 99.98
    },
]

# 首页
@app.route('/',methods=['get'])
def index():
    # 自动在templates里找对应名称的文件
    return render_template('index.html',books=books)
 
# 跳转添加页面
@app.route('/addbook',methods=['get'])
def addbook_html():
    # 自动在templates里找对应名称的文件
    return render_template('book/add.html')

# 添加
@app.route('/addbook',methods=['post'])
def addbook(): 
    # 获取json数据
    book = request.get_json() 
    # 用数组下标表示id
    book['id']= str(len(book)-1) 
    # 添加到books末尾
    books.append(book)
    return jsonify({"books":books})
         
# 删除
@app.route('/delete',methods=['delete'])
def delbook():
    id = request.args.get('id')
    # 下标
    index = -1
    # 遍历,找到id相同的元素
    for i in range(len(books)):
        if books[i]['id'] == id:
            # 记录元素下标
            index = i
    # id不是-1表示有找到要删除的元素
    if i != -1:
        # 删除
        books.remove(books[index])
        return jsonify({'books': books})
    else:
        return jsonify({'books': books})

if __name__ == "__main__":
    # 运行web服务
    app.run(host='0.0.0.0', port=10086)

index.html

我们在渲染table的时候, 将每行(tr标签)的id设为book的id, 删除时, 可以通过tr的id获取要删除的book的id, 实现删除特定的book
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<!-- 加样式,居中 -->
<style>
    * {
        margin: 0 auto;
        text-align: center;
    }
</style>

<body>
    <br>
    <table border="1">
        <thead>
            <tr>
                <th>书名</th>
                <th>作者</th>
                <th>描述</th>
                <th>价格</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            {% for book in books %} {# 遍历 books 变量 #}
            <tr id={{book.id}}>
                <th>{{book.name}}</th>
                <th>{{book.author}}</th>
                <th>{{book.desc}}</th>
                <th>{{book.price}}</th>
                <th>
                    <button id={{book.id}}>删除</button>
                    <a href='http://localhost:10086/uptbook?id={{book.id}}'>修改</a>
                </th>
            </tr>
            {% endfor %} {# 使用 endfor 标签结束 for 语句 #}
        </tbody>
    </table>
    <br>
    <a href="http://localhost:10086/addbook">添加图书</a>
    <!-- axios,可以发送请求给后端 -->
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script>
        // 按钮
        const btns = document.querySelectorAll('th > button')
        // 遍历
        btns.forEach((b) => {
            console.log(b.id);
            // 给按钮添加click事件
            b.addEventListener('click', function (e) {
                // todo 弹出确认框,是否删除
                // 删除
                axios.delete(("http://localhost:10086/delete?id=" + b.id))
                    .then((res) => {
                        if (res.status == 200 && res.data) {
                            // 刷新页面
                            location.reload();
                            alert('删除成功')
                        } else {
                            alert('删除失败')
                        }
                    })
            })
        })
    </script>
</body>

</html>

查看效果

修改图书信息

前端点击修改后跳转修改页面
<a href='http://localhost:10086/uptbook?id={{book.id}}'>修改</a>

main.py

# flask创建http接口
from flask import Flask, request, jsonify,render_template
# 支持flask跨域
from flask_cors import CORS 
# 创建flask服务
app = Flask(__name__)
CORS(app, resources=r'/*')  # 注册CORS, "/*" 允许访问域名所有api 
 
# 暂时代替数据库
books = [
    {
        "id":'1',
        "name":"hello world",
        "author":"迭名",
        "desc": "程序员入门第一本书",
        "price": 11.99
    },
    {
        "id":'2',
        "name":"0基础学it",
        "author":"xx程序员",
        "desc": "某培训机构精心出品教程",
        "price": 99.98
    },
]

# 首页
@app.route('/',methods=['get'])
def index():
    # 自动在templates里找对应名称的文件
    return render_template('index.html',books=books)
 
# 跳转添加页面
@app.route('/addbook',methods=['get'])
def addbook_html():
    # 自动在templates里找对应名称的文件
    return render_template('book/add.html')

# 添加
@app.route('/addbook',methods=['post'])
def addbook(): 
    # 获取json数据
    book = request.get_json() 
    # 用数组下标表示id
    book['id']= str(len(book)-1) 
    # 添加到books末尾
    books.append(book)
    return jsonify({"books":books})
         
# 删除
@app.route('/delete',methods=['delete'])
def delbook():
    id = request.args.get('id')
    # 下标
    index = -1
    # 遍历,找到id相同的元素
    for i in range(len(books)):
        if books[i]['id'] == id:
            # 记录元素下标
            index = i
    # id不是-1表示有找到要删除的元素
    if i != -1:
        # 删除
        books.remove(books[index])
        return jsonify({'books': books})
    else:
        return jsonify({'books': books})

# 跳转修改页面
@app.route('/uptbook',methods=['get'])
def uptbook_html():
    id = request.args.get('id') 
    book = {}
    for b in books: 
        if b['id'] == id:
            book = b
    return render_template('book/update.html',book=book)

# 修改
@app.route('/uptbook',methods=['patch'])
def uptbook():
    id = request.args.get('id') 
    book = request.get_json() 
    index = -1
    for i in range(len(books)): 
        if books[i]['id'] == id:
            index = i
    if index == -1:
        return jsonify({"books":books})
    else: 
        if(book['name']!=None):
            books[index]['name'] = book['name']
        if(book['author']!=None):
            books[index]['author'] = book['author']
        if(book['desc']!=None):
            books[index]['desc'] = book['desc']
        if(book['price']!=None):
            books[index]['price'] = book['price']
        return jsonify({"books":books}) 
        
if __name__ == "__main__":
    # 运行web服务
    app.run(host='0.0.0.0', port=10086)

update.html

和添加图书页面基本相同
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <!-- 自定义属性,值为book.id -->
    <form id="form" data-id={{book.id}}>
        <lable>书名</lable>
        <input type="text" name="book-name" value={{book.name}} id="book-name">
        <label for="">作者</label>
        <input type="text" name="book-author" value={{book.author}} id="book-author">
        <label for="">描述</label>
        <input type="text" name="book-desc" value={{book.desc}} id="book-desc">
        <label for="">价格</label>
        <input type="text" name="book-price" value={{book.price}} id="book-price">
        <button type="submit">提交</button>
    </form>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script>
        const uptform = document.querySelector("#form")
        const bookName = document.querySelector("#book-name")
        const bookDesc = document.querySelector("#book-desc")
        const bookAuthor = document.querySelector("#book-author")
        const bookPrice = document.querySelector("#book-price")
        // 自定义属性 
        const id = uptform.dataset.id
        uptform.addEventListener("submit", function (e) {
            e.preventDefault();
            // console.log(bookName.value);
            // 发送请求给后端
            axios.patch(("http://localhost:10086/uptbook?id=" + id), {
                name: bookName.value,
                author: bookAuthor.value,
                desc: bookDesc.value,
                price: bookPrice.value
            }).then((res) => {
                console.log(res);
                alert('修改成功')
                // 跳转回首页
                window.location.href = 'http://localhost:10086/'
            })
        })
    </script>
</body>

</html>

查看效果

完结, 恭喜

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux 的软件生态 软件包管理器(yum)编译器 - vim

Linux的软件生态 在 手机 ipad 笔记本等等我们使用的产品当中&#xff0c;会有应用商店等等可以下载软件的 软件包管理器&#xff0c;当我们想要下载某一款软件的时候&#xff0c;就去这个应用商店当中搜索&#xff0c;或者是去寻找&#xff0c;找到之后&#xff0c;进行下载&a…

Linux Kernel源码阅读: x86-64 系统调用实现细节(超详细)

0、前言 本文采用Linux 内核 v3.10 版本 本文不涉及调试、跟踪及异常处理的细节 一、系统调用简介 系统调用是用户空间程序与内核交互的主要机制。系统调用与普通函数调用不同&#xff0c;因为它调用的是内核里的代码。使用系统调用时&#xff0c;需要特殊指令以使处理器权限转…

初识Linux操作系统及常用的Linux命令

Linux是一种自由和开放源码的类UNIX操作系统&#xff0c;也是一种基于POSIX和Unix的多用户、多任务、支持多线程和多CPU的操作系统。伴随互联网的发展&#xff0c;企业对服务器速度和安全的要求越来越高&#xff0c;Linux系统由于具有性能稳定、防火墙组件性能高效、配置简单等…

Java内存模型的抽象结构 JMM

并发编程模型的两个关键问题 线程之间如何通信及线程之间如何同步。 线程之间如何通信&#xff1a;共享内存&#xff0c;消息传递线程之间如何同步通信是指线程之间以何种机制来 交换信息同步是指程序中用于控制不同线程间 操作发生相对顺序 的机制在共享内存的并发模型里&a…

Maven 详细教程(万字长文)

目录 一、Maven的简介二、Maven安装与配置三、Maven POM四、创建 Maven 项目五、Maven项目的构建与测试六、Maven依赖七、Maven仓库&#xff08;本地仓库远程仓库&#xff09;八、Maven生命周期&#xff08;cleansitedefault&#xff09;九、Maven常用插件十、Maven 版本号约定…

大模型时代的prompt学习(持续更新)

目录 为什么要学prompt基本原则prompt撰写框架Base Prompt FrameworkCRISPE Prompt Framework 场景撰写文案文档竞品分析产品设计数据分析 chain of thoughtzero shotin context learning(few shot)Self-Consistency Program-Aidedprompt tipsTo Do and Not To Doadd examples引…

水下图像0

d_r_1_.jpg 一个拖着电线的水下六足机器人在海水中作业 A robot is exploring the reef on the sea floor A hexapod robot works next to reef at the bottom of the sea A rectangular deep-sea robot swims past a patch of reef An underwater robot is detecting coral …

神经网络视觉AI“后时代”自瞄实现与对抗

通俗一点来说&#xff0c;自瞄是在FPS射击游戏中最为常见的作弊手段之一&#xff0c;当下最火爆的CSGO也深受其扰&#xff0c;在此我说些我自己的看法&#xff0c;欢迎大家在下方留言讨论&#xff1b; &#xff08;1&#xff09;软件层面 在神经网络方面的视觉AI应用流行之前&…

面试官:工作三年,还来面初级软件测试?恐怕你的软件测试工程师的头衔要加双引号...

相信身为测试工程师的你可能经历过这些&#xff1a; 已经工作三年了&#xff0c;每个项目都会加班加点全力以赴去完成&#xff0c;薪资增长幅度却不如人意。 听说年后离职的老同事&#xff0c;金三刚拿下高薪offer&#xff0c;年薪直奔50万了。 由于现在的公司接触不到新技术&…

docker(一)安装部署卸载以及基础命令使用

文章目录 1、安装1.1、安装插件1.2、设置源&#xff1a;1.3、安装docker卸载docker&#xff1a;1.4、配置国内源 2、基础命令3、提交某个镜像为新的镜像4、docker 存档 1、安装 机器配置: 1.1、安装插件 [rootdophin ~]# yum -y install yum-utils1.2、设置源&#xff1a; …

Spring相关面试题(Spring核心)

Spring相关面试题 谁定义了bean的生命周期IOC初始化 IOC启动阶段 (Spring容器的启动流程)Spring-IOC是什么IOC是什么DI是什么 依赖注入 DI的三种方式Spring-AOP是什么OOPAOPAOP实现方式动JDK动态代理和CGLIB动态代理 JDK动态代理和CGLIB动态代理IOC 和 AOP 的联系和区别 BeanFa…

【2023 · CANN训练营第一季】应用开发(初级)第五章——媒体数据处理

1.媒体数据处理 受网络结构和训练方式等因素的影响&#xff0c;绝大多数神经网络模型对输入数据都有格式上的限制。在计算机视觉领域&#xff0c;这个限制大多体现在图像的尺寸、色域、归一化参数等。如果源图或视频的尺寸、格式等与网络模型的要求不一致时&#xff0c;我们需…

LLMs开源模型们和数据集简介

本篇文章整理下目前常用的LLMs模型们和数据集简介。 BackBones ​https://github.com/FreedomIntelligence/LLMZoo 可以看到目前被广泛用来作为LLMs的backbone的模型有以下特点&#xff1a; Backbone&#xff1a;基于某个开源backbone&#xff0c;如GLM、LLaMA、BLOOMZ&#…

Android 文本识别:MLKIT + PreviewView

随着移动设备的普及和摄像头的高像素化&#xff0c;利用相机进行文本识别成为了一种流行的方式。MLKit 是 Google 提供的一款机器学习工具包&#xff0c;其中包含了丰富的图像和语言处理功能&#xff0c;包括文本识别。PreviewView 是 Android Jetpack 的一部分&#xff0c;它提…

2 files found with path ‘lib/arm64-v8a/libwechatbacktrace.so‘ from inputs

2 files found with path lib/arm64-v8a/libwechatbacktrace.so from inputs 解决方案&#xff0c;在app module的build.gradle里面的 android { } 块里面添加&#xff1a; packagingOptions {exclude lib/arm64-v8a/libwechatbacktrace.so} 如果有多个&#xff0c;就再增加行…

“宝石与石头”:一道简单却巧妙的力扣算法题

本篇博客会讲解力扣“771. 宝石与石头”的解题思路&#xff0c;这是题目链接。 先来审题&#xff1a; 以下是输出示例&#xff1a; 以下是提示&#xff1a; 本题可以使用数组模拟哈希表来实现。先把宝石字符串中的字符标识到数组的对应位置&#xff0c;每次拿石头字符串中的…

ChatGpt免费的镜像网站

目录 1.ChatGpt 简介 2.ChatGpt 免费网站合集 2.1 https://chat21.zhulei.xyz/ 2.2 Vega AI 创作平台 2.3 AI文本工具站 2.4 FancyPig (jqrai.one) 2.5 AiDuTu 1.ChatGpt 简介 ChatGPT是美国人工智能研究实验室OpenAI新推出的一种人工智能技术驱动的自然语言处理工具&…

geotools简介

geotools简介 官网 https://docs.geotools.org/latest/userguide/index.html 架构图 特性 1. 主要特性 Geotools主要提供各种GIS算法&#xff0c;实现各种数据格式的读写和显示。在显示方面要差一些&#xff0c;只是用Swing实现了地图的简单查看和操作。用户可以根据Geoto…

运营-17.留存

如何定义留存 某段时间内的新增用户&#xff0c;经过一段时间后&#xff0c;又继续使用应用的被认作是留存 用户&#xff0c;这部分用户占当时新增用户的比例即是留存率&#xff0c;即用户没有流失&#xff1b; 例如&#xff1a; 5月份新增用户200&#xff0c;这200人在6月份启…

Abaqus——悬臂梁问题之工字梁实例

参考 有限元基础-第7课&#xff08;悬臂梁问题&#xff09;-2022年_哔哩哔哩_bilibili 实例 软件 Abaqus 2022 方法 通过线形式建模 具体操作 建模 1.打开部件的模块&#xff0c;创建一个零件。Name&#xff1a;自定义命名&#xff1b;Modeling Space&#xff1a;梁的空…