1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 【小沐学Python】Python实现Web服务器(Flask+Vue+node.js web单页增删改查)

【小沐学Python】Python实现Web服务器(Flask+Vue+node.js web单页增删改查)

时间:2020-12-23 10:15:36

相关推荐

【小沐学Python】Python实现Web服务器(Flask+Vue+node.js web单页增删改查)

文章目录

1、简介1.1 flask1.2 vue 2、开发2.1 新建flask项目2.2 安装flask库2.3 新建flask的主脚本2.4 新建Vue项目2.5 安装vue项目依赖项2.6 新增组件Ping.vue2.7 Ping.vue增加HTTP请求2.8 美化vue前端页面2.9 新增组件Books.vue2.10 flask增加路由Books2.11 Books.vue增加HTTP请求2.12 flask修改路由Books2.13 Books.vue增加添加接口2.14 新增组件Alert.vue2.15 修改组件Alert.vue2.16 变量绑定Alert组件2.17 flask端Book对象添加唯一id2.18 Books.vue增加更新操作 结语

1、简介

1.1 flask

Flask是一个简单但功能强大的Python微Web框架,非常适合构建RESTful API。像Sinatra(Ruby)和Express(Node)一样,它是最小和灵活的,所以你可以从小处着手,然后根据需要构建更复杂的应用程序。

安装如下:

pip install flask

1.2 vue

Vue 是一个用于构建用户界面的开源 JavaScript 框架。它采用了React和Angular的一些最佳实践。也就是说,与 React 和 Angular 相比,它更平易近人,因此初学者可以快速启动和运行。它也同样强大,因此它提供了创建现代前端应用程序所需的所有功能。

安装如下:

npm create vue@3.6.1

2、开发

2.1 新建flask项目

首先创建一个新的项目目录:

mkdir flask-vue-crudcd flask-vue-crud

创建并激活虚拟环境:

python -m venv myvenv.\myvenv\Scripts\activate

2.2 安装flask库

将 Flask 与 Flask-CORS 扩展一起安装:

pip install Flask Flask-Cors

2.3 新建flask的主脚本

app.py:

# -*- coding:utf-8 -*-from flask import Flask, jsonify, make_responsefrom flask_cors import CORSclass Config(object):DEBUG=TrueJSON_AS_ASCII=False# instantiate the appapp = Flask(__name__)# app.config.from_object(__name__)app.config.from_object(Config)# app.config["JSON_AS_ASCII"] = False# app.config['DEBUG'] = True# app.config['JSONIFY_MIMETYPE'] = "application/json;charset=utf-8"# enable CORSCORS(app, resources={r'/*': {'origins': '*'}})@app.route('/', methods=['GET'])def index():response = make_response(jsonify('爱看书的小沐!'))response.headers['Content-Type'] = 'application/json;charset=utf-8'return response# return jsonify('爱看书的小沐!')# sanity check route@app.route('/ping', methods=['GET'])def ping_pong():return jsonify("xiaomu's pong!")if __name__ == '__main__':app.run(port=5001)

运行上面这个脚本:

flask run --port=5001 --debug

2.4 新建Vue项目

使用强大的create-vue工具,它使用Vite来生成一个定制的项目样板。

在 “flask-vue-crud” 中,运行以下命令来初始化一个新的 Vue 项目:

npm create vue@3.6.1

快速浏览生成的项目结构。这可能看起来很多,但我们只会处理“src”文件夹中的文件和文件夹以及index.html文件。

main.js:app 入口点,它加载并初始化 Vue 以及根组件App.vue:根组件,这是呈现所有其他组件的起点"components":UI 组件的存储位置router/index.js:定义 URL 并将其映射到组件的位置"views":绑定到路由器的 UI 组件的存储位置"assets":静态资产(如图像和字体)的存储位置

查看 client/src/components/HelloWorld.vue 文件。这是一个单个文件组件,分为三个不同的部分:

模板:用于特定于组件的 HTML脚本:组件逻辑通过JavaScript实现样式:用于 CSS 样式

其中index.html 文件是我们 Vue 应用程序的起点:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><link rel="icon" href="/favicon.ico"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vite App</title></head><body><div id="app"></div><script type="module" src="/src/main.js"></script></body></html>

2.5 安装vue项目依赖项

$ cd vue-project$ npm install$ npm run dev

浏览器访问如下:

2.6 新增组件Ping.vue

为了简化操作,请删除“vue-project/src/views”和“vue-project/src/components/icons”文件夹以及vue-project/src/components/TheWelcome.vue和vue-project/src/components/WelcomeItem.vue组件。然后,将一个名为 Ping.vue 的新组件添加到名为 Ping.vue 的“vue-project/src/components”文件夹中:

<template><div><p>{{msg }}</p></div></template><script>export default {name: 'Ping',data() {return {msg: 'Hello!',};},};</script>

更新客户端/src/router/index.js将“/ping”映射到组件,如下所示:

import {createRouter, createWebHistory } from 'vue-router'import Ping from '../components/Ping.vue'const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: [{path: '/ping',name: 'ping',component: Ping},]})export default router

最后,在 vue-project/src/App.vue 中,删除导航以及样式:

<template><RouterView /></template><script setup>import {RouterView } from 'vue-router'</script>

在浏览器访问: http://localhost:5173/ping

2.7 Ping.vue增加HTTP请求

要将客户端 Vue 应用程序与后端 Flask 应用程序连接起来,我们可以使用 Axios 库发送 HTTP 请求。

npm install axios@1.3.6 --save

在 Ping.vue 中更新组件的部分,如下所示:

<template><div><p>{{msg }}</p></div></template><script>import axios from 'axios';export default {name: 'Ping',data() {return {msg: '',};},methods: {getMessage() {const path = 'http://localhost:5001/ping';axios.get(path).then((res) => {this.msg = res.data;}).catch((error) => {console.error(error);});},},created() {this.getMessage();},};</script>

随着 Vue 应用程序在不同的终端窗口中运行,您现在应该在浏览器中看到。

2.8 美化vue前端页面

接下来,让我们将 Bootstrap(一个流行的 CSS 框架)添加到应用程序中,以便我们可以快速添加一些样式。

npm install bootstrap@5.2.3 --save

将引导程序样式导入客户端/src/main.js:

import {createApp } from 'vue'import App from './App.vue'import router from './router'import 'bootstrap/dist/css/bootstrap.css' //add by tomcatimport './assets/main.css'const app = createApp(App)app.use(router)app.mount('#app')

更新vue-project\src\components\Ping.vue的template部分:

<template><div class="container"><button type="button" class="btn btn-primary">{{msg }}</button></div></template>

运行开发服务器:

2.9 新增组件Books.vue

<template><div class="container"><div class="row"><div class="col-sm-10"><h1>Books</h1><hr><br><br><button type="button" class="btn btn-success btn-sm">Add Book</button><br><br><table class="table table-hover"><thead><tr><th scope="col">Title</th><th scope="col">Author</th><th scope="col">Read?</th><th></th></tr></thead><tbody><tr><td>foo</td><td>bar</td><td>foobar</td><td><div class="btn-group" role="group"><button type="button" class="btn btn-warning btn-sm">Update</button><button type="button" class="btn btn-danger btn-sm">Delete</button></div></td></tr></tbody></table></div></div></div></template>

修改路由文件:vue-project\src\router\index.js

import {createRouter, createWebHistory } from 'vue-router'import Books from '../components/Books.vue'import Ping from '../components/Ping.vue'const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: [{path: '/',name: 'Books',component: Books,},{path: '/ping',name: 'ping',component: Ping},]})export default router

浏览器访问:http://localhost:5173

2.10 flask增加路由Books

app.py:

BOOKS = [{'title': 'On the Road','author': 'Jack Kerouac','read': True},{'title': 'Harry Potter and the Philosopher\'s Stone','author': 'J. K. Rowling','read': False},{'title': 'Green Eggs and Ham','author': 'Dr. Seuss','read': True}]@app.route('/books', methods=['GET'])def all_books():return jsonify({'status': 'success','books': BOOKS})

浏览器访问如下:

2.11 Books.vue增加HTTP请求

<template><div class="container"><div class="row"><div class="col-sm-10"><h1>Books</h1><hr><br><br><button type="button" class="btn btn-success btn-sm">Add Book</button><br><br><table class="table table-hover"><thead><tr><th scope="col">Title</th><th scope="col">Author</th><th scope="col">Read?</th><th></th></tr></thead><tbody><tr v-for="(book, index) in books" :key="index"><td>{{book.title }}</td><td>{{book.author }}</td><td><span v-if="book.read">Yes</span><span v-else>No</span></td><td><div class="btn-group" role="group"><button type="button" class="btn btn-warning btn-sm">Update</button><button type="button" class="btn btn-danger btn-sm">Delete</button></div></td></tr></tbody></table></div></div></div></template><script>import axios from 'axios';export default {data() {return {books: [],};},methods: {getBooks() {const path = 'http://localhost:5001/books';axios.get(path).then((res) => {this.books = res.data.books;}).catch((error) => {console.error(error);});},},created() {this.getBooks();},};</script>

浏览器访问如下:

2.12 flask修改路由Books

from flask import Flask, jsonify, request@app.route('/books', methods=['GET', 'POST'])def all_books():response_object = {'status': 'success'}if request.method == 'POST':post_data = request.get_json()BOOKS.append({'title': post_data.get('title'),'author': post_data.get('author'),'read': post_data.get('read')})response_object['message'] = 'Book added!'else:response_object['books'] = BOOKSreturn jsonify(response_object)

运行 Flask 服务器后,您可以在新的终端选项卡中测试 POST 路由:

curl -X POST http://localhost:5001/books -d "{\"title\": \"1024\", \"author\": \"Xiao Mu\", \"read\": \"true\"}" -H "Content-Type: application/json"

命令行输入curl指令如下:

flask的web服务端的信息输出如下:

vue前端页面的最下面增加了一行记录如下:

2.13 Books.vue增加添加接口

<template><div class="container"><div class="row"><div class="col-sm-10"><h1>Books</h1><hr><br><br><buttontype="button"class="btn btn-success btn-sm"@click="toggleAddBookModal">Add Book</button><br><br><table class="table table-hover"><thead><tr><th scope="col">Title</th><th scope="col">Author</th><th scope="col">Read?</th><th></th></tr></thead><tbody><tr v-for="(book, index) in books" :key="index"><td>{{book.title }}</td><td>{{book.author }}</td><td><span v-if="book.read">Yes</span><span v-else>No</span></td><td><div class="btn-group" role="group"><button type="button" class="btn btn-warning btn-sm">Update</button><button type="button" class="btn btn-danger btn-sm">Delete</button></div></td></tr></tbody></table></div></div><!-- add new book modal --><divref="addBookModal"class="modal fade":class="{ show: activeAddBookModal, 'd-block': activeAddBookModal }"tabindex="-1"role="dialog"><div class="modal-dialog" role="document"><div class="modal-content"><div class="modal-header"><h5 class="modal-title">Add a new book</h5><buttontype="button"class="close"data-dismiss="modal"aria-label="Close"@click="toggleAddBookModal"><span aria-hidden="true">&times;</span></button></div><div class="modal-body"><form><div class="mb-3"><label for="addBookTitle" class="form-label">Title:</label><inputtype="text"class="form-control"id="addBookTitle"v-model="addBookForm.title"placeholder="Enter title"></div><div class="mb-3"><label for="addBookAuthor" class="form-label">Author:</label><inputtype="text"class="form-control"id="addBookAuthor"v-model="addBookForm.author"placeholder="Enter author"></div><div class="mb-3 form-check"><inputtype="checkbox"class="form-check-input"id="addBookRead"v-model="addBookForm.read"><label class="form-check-label" for="addBookRead">Read?</label></div><div class="btn-group" role="group"><buttontype="button"class="btn btn-primary btn-sm"@click="handleAddSubmit">Submit</button><buttontype="button"class="btn btn-danger btn-sm"@click="handleAddReset">Reset</button></div></form></div></div></div></div><div v-if="activeAddBookModal" class="modal-backdrop fade show"></div></div></template><script>import axios from 'axios';export default {data() {return {activeAddBookModal: false,addBookForm: {title: '',author: '',read: [],},books: [],};},methods: {addBook(payload) {const path = 'http://localhost:5001/books';axios.post(path, payload).then(() => {this.getBooks();}).catch((error) => {console.log(error);this.getBooks();});},getBooks() {const path = 'http://localhost:5001/books';axios.get(path).then((res) => {this.books = res.data.books;}).catch((error) => {console.error(error);});},handleAddReset() {this.initForm();},handleAddSubmit() {this.toggleAddBookModal();let read = false;if (this.addBookForm.read[0]) {read = true;}const payload = {title: this.addBookForm.title,author: this.addBookForm.author,read, // property shorthand};this.addBook(payload);this.initForm();},initForm() {this.addBookForm.title = '';this.addBookForm.author = '';this.addBookForm.read = [];},toggleAddBookModal() {const body = document.querySelector('body');this.activeAddBookModal = !this.activeAddBookModal;if (this.activeAddBookModal) {body.classList.add('modal-open');} else {body.classList.remove('modal-open');}},},created() {this.getBooks();},};</script>

2.14 新增组件Alert.vue

让我们添加一个组件,以便在添加新书籍后向最终用户显示消息。我们将为此创建一个新组件Alert.vue,因为您可能会在许多组件中使用该功能。

将一个名为 Alert.vue 的新文件添加到 “vue-project/src/components”:

<template><p>It works!爱看书的小沐正在添加Alert</p></template>

然后,将其添加到Books.vue中:

<script>import axios from 'axios';import Alert from './Alert.vue';export default {data() {return {activeAddBookModal: false,addBookForm: {title: '',author: '',read: [],},books: [],};},components: {alert: Alert,},...};</script>

在Books.vue的template部分也添加Alert的使用:

<template><div class="container"><div class="row"><div class="col-sm-10"><h1>Books</h1><hr><br><br><alert></alert><buttontype="button"class="btn btn-success btn-sm"@click="toggleAddBookModal">Add Book</button><br><br>...</div></div>...</div></template>

前端预览如下:

2.15 修改组件Alert.vue

<template><div><div class="alert alert-success" role="alert">{{message }}</div><br/></div></template><script>export default {props: ['message'],};</script>

同时修改Books.vue的template部分中的alert代码:

<alert message="hi, 爱看书的小沐"></alert>

2.16 变量绑定Alert组件

Books.vue 中使用绑定表达式。修改Books.vue的template部分中的alert代码:

<alert :message="message"></alert>

修改Books.vue的script的data()函数:

data() {return {activeAddBookModal: false,addBookForm: {title: '',author: '',read: [],},books: [],message: '',};},

修改Books.vue的script的addBook()函数:

addBook(payload) {const path = 'http://localhost:5001/books';axios.post(path, payload).then(() => {this.getBooks();this.message = 'Book added!';}).catch((error) => {console.log(error);this.getBooks();});},

仅在 true 时显示警报:v-ifshowMessage:

<alert :message=message v-if="showMessage"></alert>

data() {return {activeAddBookModal: false,addBookForm: {title: '',author: '',read: [],},books: [],message: '',showMessage: false,};},

addBook(payload) {const path = 'http://localhost:5001/books';axios.post(path, payload).then(() => {this.getBooks();this.message = 'Book added!';this.showMessage = true;}).catch((error) => {console.log(error);this.getBooks();});},

2.17 flask端Book对象添加唯一id

import uuidBOOKS = [{'id': uuid.uuid4().hex,'title': 'On the Road','author': 'Jack Kerouac','read': True},]@app.route('/books', methods=['GET', 'POST'])def all_books():response_object = {'status': 'success'}if request.method == 'POST':post_data = request.get_json()BOOKS.append({'id': uuid.uuid4().hex,'title': post_data.get('title'),'author': post_data.get('author'),'read': post_data.get('read')})response_object['message'] = 'Book added!'else:response_object['books'] = BOOKSreturn jsonify(response_object)@app.route('/books/<book_id>', methods=['PUT'])def single_book(book_id):response_object = {'status': 'success'}if request.method == 'PUT':post_data = request.get_json()remove_book(book_id)BOOKS.append({'id': uuid.uuid4().hex,'title': post_data.get('title'),'author': post_data.get('author'),'read': post_data.get('read')})response_object['message'] = 'Book updated!'return jsonify(response_object)def remove_book(book_id):for book in BOOKS:if book['id'] == book_id:BOOKS.remove(book)return Truereturn False

2.18 Books.vue增加更新操作

template部分增加:

<!-- edit book modal --><divref="editBookModal"class="modal fade":class="{ show: activeEditBookModal, 'd-block': activeEditBookModal }"tabindex="-1"role="dialog"><div class="modal-dialog" role="document"><div class="modal-content"><div class="modal-header"><h5 class="modal-title">Update</h5><buttontype="button"class="close"data-dismiss="modal"aria-label="Close"@click="toggleEditBookModal"><span aria-hidden="true">&times;</span></button></div><div class="modal-body"><form><div class="mb-3"><label for="editBookTitle" class="form-label">Title:</label><inputtype="text"class="form-control"id="editBookTitle"v-model="editBookForm.title"placeholder="Enter title"></div><div class="mb-3"><label for="editBookAuthor" class="form-label">Author:</label><inputtype="text"class="form-control"id="editBookAuthor"v-model="editBookForm.author"placeholder="Enter author"></div><div class="mb-3 form-check"><inputtype="checkbox"class="form-check-input"id="editBookRead"v-model="editBookForm.read"><label class="form-check-label" for="editBookRead">Read?</label></div><div class="btn-group" role="group"><buttontype="button"class="btn btn-primary btn-sm"@click="handleEditSubmit">Submit</button><buttontype="button"class="btn btn-danger btn-sm"@click="handleEditCancel">Cancel</button></div></form></div></div></div></div><div v-if="activeEditBookModal" class="modal-backdrop fade show"></div>

script部分增加:

activeEditBookModal: false,editBookForm: {id: '',title: '',author: '',read: [],},

template部分的主界面修改:

<buttontype="button"class="btn btn-warning btn-sm"@click="toggleEditBookModal(book)">Update</button>

script部分增加函数:

toggleEditBookModal(book) {if (book) {this.editBookForm = book;}const body = document.querySelector('body');this.activeEditBookModal = !this.activeEditBookModal;if (this.activeEditBookModal) {body.classList.add('modal-open');} else{body.classList.remove('modal-open');}},handleEditSubmit() {this.toggleEditBookModal(null);let read = false;if (this.editBookForm.read) read = true;const payload = {title: this.editBookForm.title,author: this.editBookForm.author,read,};this.updateBook(payload, this.editBookForm.id);},updateBook(payload, bookID) {const path = `http://localhost:5001/books/${bookID}`;axios.put(path, payload).then(() => {this.getBooks();this.message = 'Book updated!';this.showMessage = true;}).catch((error) => {console.error(error);this.getBooks();});},handleEditCancel() {this.toggleEditBookModal(null);this.initForm();this.getBooks(); // why?},

修改函数initForm():

initForm() {this.addBookForm.title = '';this.addBookForm.author = '';this.addBookForm.read = [];this.editBookForm.id = '';this.editBookForm.title = '';this.editBookForm.author = '';this.editBookForm.read = [];},

浏览器预览如下:

结语

如果您觉得该方法或代码有一点点用处,可以给作者点个赞,或打赏杯咖啡;╮( ̄▽ ̄)╭

如果您感觉方法或代码不咋地//(ㄒoㄒ)//,就在评论处留言,作者继续改进;o_O???

如果您需要相关功能的代码定制化开发,可以留言私信作者;(✿◡‿◡)

感谢各位大佬童鞋们的支持!( ´ ▽´ )ノ ( ´ ▽´)っ!!!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。