赞
踩
该webui的主要作用是作为一个数据库管理系统对本地mysql数据库进行管理。这里会手把手教学如何实现的,并在文末给出初代完整flask数据库管理系统的完整代码!希望能帮助到有需要的同学。本来是想用来干点其他的,但是想了一下决定还是完整开源出来,各位看官,用的话记得给个鸣谢或者引用呗!Thanks♪(・ω・)ノ
注:本人软工部分也是刚学习不久,代码规范和代码维护上存在欠缺,还需看官多多包涵,恳请批评指正!
这是我的界面截图(背景随便找的)
登录界面:
数据库选择界面:
数据库管理界面:
搜索结果:
现在我们开始
首先,先安装mysql数据库,这里给出一个windows的下载链接,我选择的是mysql8.4.0.lts版本,MySQL :: Download MySQL Community Server
以及mysql workbench-mysql的可视化界面
MySQL :: Download MySQL Workbench
下载后根据安装指引安装即可,记得先给设置一个从用户账户和密码,该账户用来给flask连接数据库。记住保存路径,并勾选world数据库(方便后期调试)
然后设置系统环境变量,右键此电脑→高级系统设置→系统变量设置→系统变量→path→新建→粘贴刚才的保存路径(默认是C:\Program Files\MySQL\MySQL Server 8.4\bin,需要查看该目录下是否存在mysql.exe)
mysql安装好后按道理理论上会自动启动,不过也可以通过win+r输入services.msc查询,找到mysql开头的,我的是MySQL84,右键属性可以看到
这样就可以了。
然后试一下,找一个空白的地方shift+右键,打开powershell,然后键入 mysql -u root账户名 -p,然后输入密码验证。显示<mysql>即成功安装。
然后就是python,python的安装自行搜索,不做过多停留,安装完python后给pip换为国内源,
windows环境下: 比如windows账号是 admin
那么建立 admin主目录下的 pip子目录,在此pip子目录下建立pip的配置文件:pip.ini
位于c:\users\admin\pip\pip.ini
# coding: GBK
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple
[install]
trusted-host = https://pypi.tuna.tsinghua.edu.cn
#清华大学:https://pypi.tuna.tsinghua.edu.cn/simple
#阿里云:http://mirrors.aliyun.com/pypi/simple/
#豆瓣:http://pypi.douban.com/simple/
=================================================================
推荐采用python虚拟环境中执行该系统环境配置
创建一个工程目录,并在该目录下执行powershell(shift + 右键)或者终端(ctrl+alt+T)
python -m venv venv
venv/script/activate
安装flask框架(mysql):
pip install flask
pip install mysql-connector-python
pip install Flask mysql-connector-python
pip install Flask-Session
这样环境就配置好了
然后就是执行python文件,python app.py
如果终端显示
则表示运行成功,并可在浏览器输入http://127.0.0.1:5000访问。
以下是app.py的示例代码:
- ################################app.py############################
- from flask import Flask, request, jsonify, render_template, redirect, url_for, session
- from flask_session import Session
- import mysql.connector
-
- app = Flask(__name__)
- app.secret_key = 'root' # 用于会话管理
- app.config['SESSION_TYPE'] = 'filesystem' # 使用文件系统存储会话
- Session(app)
-
- # 预定义账号和密码
- USERS = {
- 'admin': 'admin',
- '旅馆管理系统': '123456'
- }
-
- # 数据库连接配置
- db_config = {
- 'host': 'localhost',
- 'user': '旅馆管理系统',
- 'password': '123456'
- }
-
- def get_db_connection():
- conn = mysql.connector.connect(
- host=db_config['host'],
- user=db_config['user'],
- password=db_config['password']
- )
- return conn
-
- def get_databases():
- conn = get_db_connection()
- cursor = conn.cursor()
- cursor.execute("SHOW DATABASES")
- databases = [database[0] for database in cursor.fetchall() if database[0] != 'information_schema'] # 排除系统数据库
- cursor.close()
- conn.close()
- return databases
-
- def get_tables(database):
- conn = get_db_connection()
- cursor = conn.cursor()
- cursor.execute(f"USE {database}")
- cursor.execute("SHOW TABLES")
- tables = [table[0] for table in cursor.fetchall()]
- cursor.close()
- conn.close()
- return tables
-
- def get_table_fields(database, table):
- conn = get_db_connection()
- cursor = conn.cursor()
- cursor.execute(f"USE {database}")
- cursor.execute(f"SHOW COLUMNS FROM {table}")
- fields = [field[0] for field in cursor.fetchall()]
- cursor.close()
- conn.close()
- return fields
-
- def get_table_records(database, table):
- conn = get_db_connection()
- cursor = conn.cursor(dictionary=True)
- cursor.execute(f"USE {database}")
- cursor.execute(f"SELECT * FROM {table}")
- records = cursor.fetchall()
- cursor.close()
- conn.close()
- return records
-
- # 获取表的主键字段
- def get_table_primary_key(database, table):
- conn = get_db_connection()
- cursor = conn.cursor()
- cursor.execute(f"USE {database}")
- cursor.execute(f"SHOW KEYS FROM {table} WHERE Key_name = 'PRIMARY'")
- primary_key = cursor.fetchone()
- cursor.close()
- conn.close()
- return primary_key[4] if primary_key else None
-
- # 用户登录页
- @app.route('/', methods=['GET', 'POST'])
- def login():
- if request.method == 'POST':
- username = request.form['username']
- password = request.form['password']
-
- if username in USERS and USERS[username] == password:
- session['username'] = username # 将用户名存储在session中
- return redirect(url_for('home'))
- else:
- return 'Invalid username or password', 401
-
- return render_template('login.html')
-
- # 用户登出页
- @app.route('/logout')
- def logout():
- session.pop('username', None) # 清除会话数据
- return redirect(url_for('login'))
-
- # 用户管理页
- @app.route('/home')
- def home():
- if 'username' not in session:
- return redirect(url_for('login'))
- return render_template('index.html', databases=get_databases())
-
- # 进入数据库
- @app.route('/enter-database', methods=['POST'])
- def enter_database():
- if 'username' not in session:
- return redirect(url_for('login'))
-
- selected_database = request.form.get('database')
- session['selected_database'] = selected_database
- return redirect(url_for('database_home'))
-
- # 数据库主页
- @app.route('/database_home')
- def database_home():
- if 'username' not in session or 'selected_database' not in session:
- return redirect(url_for('login'))
-
- selected_database = session['selected_database']
- tables = get_tables(selected_database)
- selected_table = request.args.get('table', tables[0] if tables else None)
- fields = get_table_fields(selected_database, selected_table) if selected_table else []
- records = get_table_records(selected_database, selected_table) if selected_table else []
- primary_key = get_table_primary_key(selected_database, selected_table)
-
- return render_template('database_home.html',
- database=selected_database,
- tables=tables,
- selected_table=selected_table,
- fields=fields,
- records=records,
- field_names=fields,
- primary_key=primary_key) # 将主键字段传递给模板
-
- # 获取表的字段
- @app.route('/get_table_fields', methods=['POST'])
- def get_table_fields_route():
- if 'username' not in session or 'selected_database' not in session:
- return redirect(url_for('login'))
-
- database = session['selected_database']
- table = request.form.get('table')
- fields = get_table_fields(database, table)
- return jsonify(fields)
-
- # 保存记录
- @app.route('/save_record', methods=['POST'])
- def save_record():
- if 'username' not in session or 'selected_database' not in session:
- return jsonify({'success': False, 'error': 'Unauthorized'}), 403
-
- data = request.get_json()
- database = data['database']
- table = data['table']
- record = data['record']
-
- print("Saving record:", record) # 添加调试输出
-
- if 'id' not in record:
- return jsonify({'success': False, 'error': 'Missing id'}), 400
-
- conn = get_db_connection()
- cursor = conn.cursor()
-
- update_query = f"UPDATE {database}.{table} SET "
- update_query += ", ".join([f"{field} = %s" for field in record.keys() if field != 'id'])
- update_query += " WHERE id = %s"
- params = [record[field] for field in record.keys() if field != 'id'] + [record['id']]
-
- try:
- cursor.execute(update_query, params)
- conn.commit()
- success = True
- except Exception as e:
- print(e)
- success = False
-
- cursor.close()
- conn.close()
-
- return jsonify({'success': success})
-
- # 删除记录
- @app.route('/delete_record', methods=['POST'])
- def delete_record():
- if 'username' not in session or 'selected_database' not in session:
- return jsonify({'success': False, 'error': 'Unauthorized'}), 403
-
- data = request.get_json()
- database = data['database']
- table = data['table']
- record_name = data['name'] # 修改为 'name' 字段
-
- print("Deleting record with name:", record_name) # 添加调试输出
-
- conn = get_db_connection()
- cursor = conn.cursor()
-
- delete_query = f"DELETE FROM {database}.{table} WHERE Name = %s" # 使用 'Name' 字段作为唯一标识
-
- try:
- cursor.execute(delete_query, (record_name,))
- conn.commit()
- success = True
- except Exception as e:
- print(e)
- success = False
-
- cursor.close()
- conn.close()
-
- return jsonify({'success': success})
-
- # 保存新记录
- @app.route('/save_new_record', methods=['POST'])
- def save_new_record():
- if 'username' not in session or 'selected_database' not in session:
- return jsonify({'success': False, 'error': 'Unauthorized'}), 403
-
- data = request.get_json()
- database = data['database']
- table = data['table']
- record = data['record']
-
- print("Saving new record:", record) # 添加调试输出
-
- # 构造插入记录的 SQL 查询语句
- insert_query = f"INSERT INTO {database}.{table} ({', '.join(record.keys())}) VALUES ({', '.join(['%s']*len(record))})"
- params = tuple(record.values()) # 将记录的值转换为元组形式
-
- conn = get_db_connection()
- cursor = conn.cursor()
-
- try:
- cursor.execute(insert_query, params)
- conn.commit()
- success = True
- except Exception as e:
- print(e)
- success = False
-
- cursor.close()
- conn.close()
-
- return jsonify({'success': success})
-
- # 执行搜索并返回结果
- def search_records(database, table, keyword):
- conn = get_db_connection()
- cursor = conn.cursor(dictionary=True)
-
- # 构造模糊搜索的 SQL 查询语句
- search_query = f"SELECT * FROM {database}.{table} WHERE "
- search_query += " OR ".join([f"{field} LIKE %s" for field in get_table_fields(database, table)])
- params = ['%' + keyword + '%'] * len(get_table_fields(database, table))
-
- cursor.execute(search_query, params)
- records = cursor.fetchall()
-
- cursor.close()
- conn.close()
-
- return records
-
- # 搜索页面
- @app.route('/search_results')
- def search_results():
- if 'username' not in session or 'selected_database' not in session:
- return redirect(url_for('login'))
-
- selected_database = session['selected_database']
- selected_table = request.args.get('table')
- keyword = request.args.get('keyword')
-
- records = search_records(selected_database, selected_table, keyword)
- fields = get_table_fields(selected_database, selected_table)
-
- return render_template('search_results.html',
- keyword=keyword,
- database=selected_database,
- selected_table=selected_table,
- fields=fields,
- records=records)
-
- if __name__ == '__main__':
- app.run(debug=True)
以下是一些示例html
- ####################database_home.html#########################
- <!DOCTYPE html>
- <html lang="en">
-
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Database Home</title>
- <style>
- body {
- margin: 0;
- padding: 0;
- font-family: Arial, sans-serif;
- background-image: url('/static/background.jpg');
- background-size: cover;
- background-position: center;
- background-attachment: fixed;
- height: 100vh;
- overflow: auto;
- }
-
- .container {
- background-color: rgba(255, 255, 255, 0.8);
- padding: 20px;
- border-radius: 10px;
- box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
- margin: 20px;
- }
-
- h2 {
- margin-bottom: 10px;
- font-size: 24px;
- }
-
- button {
- padding: 12px 24px;
- cursor: pointer;
- border: none;
- border-radius: 5px;
- font-size: 18px;
- outline: none;
- transition: background-color 0.3s ease;
- }
-
- .go-back-button {
- background-color: #dc3545;
- color: #fff;
- margin-bottom: 20px;
- text-align: right;
- font-size: 18px;
- }
-
- .go-back-button:hover {
- background-color: #c82333;
- text-align: right;
- }
-
- .search-form-container,
- .table-select-container {
- text-align: left;
- margin-bottom: 50px;
- }
-
- input[type="text"],
- select {
- width: calc(100% - 120px);
- padding: 10px;
- margin-bottom: 10px;
- box-sizing: border-box;
- border: 1px solid #ccc;
- border-radius: 5px;
- background-color: #f8f8f8;
- font-size: 18px;
- outline: none;
- }
-
- button[type="submit"] {
- padding: 12px 24px;
- cursor: pointer;
- border: none;
- border-radius: 5px;
- background-color: #007bff;
- color: #fff;
- font-size: 18px;
- outline: none;
- transition: background-color 0.3s ease;
- }
-
- button[type="submit"]:hover {
- background-color: #0056b3;
- }
-
- table {
- width: 100%;
- border-collapse: collapse;
- margin-top: 10px;
- }
-
- th,
- td {
- border: 1px solid black;
- padding: 8px;
- text-align: left;
- }
-
- th {
- background-color: #f2f2f2;
- }
-
- .editable {
- background-color: #e8f0fe;
- }
-
- #new-record-table {
- display: none;
- margin-top: 20px;
- }
-
- #new-record-table td {
- width: 150px;
- padding: 5px;
- }
-
- .icon-button {
- background: none;
- border: none;
- cursor: pointer;
- padding: 0;
- outline: none;
- }
-
- .icon-button img {
- width: 48px;
- /* 调整SVG图标的尺寸 */
- height: 48px;
- /* 调整SVG图标的尺寸 */
- }
-
- .divider {
- border-top: 2px solid #ccc;
- margin-top: 20px;
- margin-bottom: 20px;
- }
-
- .footer {
- position: fixed;
- bottom: 0;
- width: 100%;
- background-color: #d6dce1;
- padding: 10px 0;
- text-align: center;
- font-size: 14px;
- color: #6c757d;
- }
- </style>
- </head>
-
- <body>
- <div class="footer">
- Version 1.0.0
- </div>
-
- <div id="user-info"
- style="position: absolute; top: 10px; right: 10px; padding: 10px; background-color: #3ec83e; border: 1px solid #007bff; border-radius: 5px;">
- <span style="color: #0b0808; font-weight: bold;">你好!{{ session['username'] }}</span>
- </div>
-
- <div class="container">
- <h2 style="font-size: 50px; font-weight: bold;">当前数据库:{{ database }}</h2>
- <button class="go-back-button" style="float: right; background-color:#d05d63;"
- onclick="goBack()">退出当前数据库</button>
- <div class="search-form-container">
- <form id="search-form" onsubmit="search(event)">
- <input type="text" id="keyword" name="keyword" placeholder="搜索..."
- style="height=45px; padding: 10px; border: 2px solid #ccc; border-radius: 10px; font-size: 16px;">
- <input type="hidden" name="table" value="{{ selected_table }}">
- <button type="submit" style="background-color:#a099dd;">搜索</button>
- </form>
- </div>
-
- <div class="table-select-container" style="display: flex; align-items: center; margin-top: 20px;">
- <label for="table-select" style="font-size: 20px; margin-right: 10px;"><strong>当前访问的表:</strong></label>
- <select id="table-select" name="table" onchange="updateTable(this.value)"
- style="font-size: 20px; width: 200px;">
- {% for table in tables %}
- <option value="{{ table }}" {% if table==selected_table %}selected{% endif %}>{{ table }}</option>
- {% endfor %}
- </select>
- </div>
-
- <button class="icon-button" onclick="toggleNewRecordForm()" style="text-align: center;">
- <img src="/static/svg/档案.svg" alt="添加记录" style="vertical-align: middle;">
- <br>
- <span id="toggle-text" style="font-size: 20px; font-weight: bold;">{{ '添加记录明细' if button_new_record_activate
- else '添加记录' }}</span>
- </button>
-
-
- <div id="new-record-table">
- <h3>添加记录</h3>
- <table id="new-record-form">
- <tbody>
- {% for field in field_names %}
- <tr>
- <td>{{ '*' if field == primary_key else '' }}{{ field }}</td>
- <td><input type="text" id="new-{{ field }}" name="{{ field }}"></td>
- </tr>
- {% endfor %}
- <tr>
- <td colspan="2" style="text-align: center;"><button class="icon-button"
- onclick="saveNewRecord()"><img src="/static/svg/上传.svg" alt="保存"></button></td>
- </tr>
- </tbody>
- </table>
- </div>
-
- <div class="divider"></div>
-
- <h3>记录列表</h3>
- <table id="record-list">
- <thead>
- <tr>
- {% for field in fields %}
- <th>{{ field }}</th>
- {% endfor %}
- <th>保存修改</th>
- <th>删除</th>
- </tr>
- </thead>
- <tbody>
- {% for record in records %}
- <tr>
- {% for field in fields %}
- <td contenteditable="true" data-field="{{ field }}">{{ record[field] }}</td>
- {% endfor %}
- <td><button class="icon-button" onclick="saveRecord(this)"><img src="/static/svg/编辑.svg"
- alt="保存"></button></td>
- <td><button class="icon-button" onclick="confirmDelete(this)"><img src="/static/svg/删除.svg"
- alt="删除"></button></td>
- </tr>
- {% endfor %}
- </tbody>
- </table>
- </div>
-
- <script>
- let button_new_record_activate = false;
-
- function toggleNewRecordForm() {
- button_new_record_activate = !button_new_record_activate;
- document.getElementById('new-record-table').style.display = button_new_record_activate ? 'block' : 'none';
- }
-
- function updateTable(table) {
- const urlParams = new URLSearchParams(window.location.search);
- urlParams.set('table', table);
- window.location.search = urlParams.toString();
- }
-
- function saveRecord(button) {
- const row = button.closest('tr');
- const fields = {};
- row.querySelectorAll('td[data-field]').forEach(td => {
- const fieldName = td.getAttribute('data-field');
- fields[fieldName.toLowerCase()] = td.innerText;
- });
-
- fetch('/save_record', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify({
- database: '{{ database }}',
- table: '{{ selected_table }}',
- record: fields
- })
- })
- .then(response => response.json())
- .then(data => {
- if (data.success) {
- alert('记录保存成功');
- } else {
- alert('记录保存失败');
- }
- });
- }
-
- function confirmDelete(button) {
- if (confirm("确定要删除吗?")) {
- deleteRecord(button);
- } else {
- // 用户取消删除操作
- }
- }
-
- function deleteRecord(button) {
- const row = button.closest('tr');
- const recordName = row.querySelector('td[data-field="Name"]').innerText;
-
- fetch('/delete_record', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify({
- database: '{{ database }}',
- table: '{{ selected_table }}',
- name: recordName
- })
- })
- .then(response => response.json())
- .then(data => {
- if (data.success) {
- alert('记录删除成功');
- row.remove();
- } else {
- alert('记录删除失败');
- }
- });
- }
-
- function search(event) {
- event.preventDefault();
-
- const keyword = document.getElementById('keyword').value.trim();
- if (keyword === '') {
- alert('请输入搜索关键字');
- return;
- }
-
- const formData = new FormData(document.getElementById('search-form'));
- const searchParams = new URLSearchParams(formData).toString();
- window.location.href = `/search_results?${searchParams}`;
- }
-
- function showNewRecordForm() {
- document.getElementById('new-record-table').style.display = 'block';
- }
-
- function saveNewRecord() {
- const record = {};
- {% for field in field_names %}
- record['{{ field }}'] = document.getElementById('new-{{ field }}').value;
- {% endfor %}
-
- fetch('/save_new_record', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify({
- database: '{{ database }}',
- table: '{{ selected_table }}',
- record: record
- })
- })
- .then(response => response.json())
- .then(data => {
- if (data.success) {
- alert('数据保存成功');
- window.location.href = `/database_home?table={{ selected_table }}`;
- } else {
- alert('数据保存失败,请检查填写的数据格式或关键字错误');
- }
- });
- }
-
- function goBack() {
- window.location.href = '/home';
- }
-
- function toggleNewRecordForm() {
- button_new_record_activate = !button_new_record_activate;
- document.getElementById('new-record-table').style.display = button_new_record_activate ? 'block' : 'none';
- document.getElementById('toggle-text').innerText = button_new_record_activate ? '收起添加记录明细' : '添加记录';
- }
-
- </script>
- </body>
-
- </html>
- ##############################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>
- <style>
- body {
- display: flex;
- justify-content: center;
- align-items: center;
- height: 100vh;
- margin: 0;
- background-image: url('/static/background.jpg');
- background-size: cover;
- background-position: center;
- background-repeat: no-repeat;
- }
-
- .container {
- background-color: rgba(255, 255, 255, 0.8);
- padding: 20px;
- border-radius: 10px;
- box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
- margin: 20px;
- width: 50%;
- /* 设置容器的宽度为页面宽度的 80% */
- }
-
-
- form {
- display: inline-block;
- text-align: left;
- width: 100%;
- }
-
- label {
- display: block;
- margin-bottom: 5px;
- font-weight: bold;
- }
-
- input[type="text"],
- input[type="password"],
- select {
- width: 100%;
- padding: 10px;
- margin-bottom: 20px;
- box-sizing: border-box;
- border: 1px solid #ccc;
- border-radius: 5px;
- background-color: #f8f8f8;
- font-size: 16px;
- outline: none;
- }
-
- .button-container {
- display: flex;
- justify-content: space-between;
- }
-
- button[type="submit"],
- .logout-button {
- padding: 10px 40px;
- cursor: pointer;
- border: none;
- border-radius: 5px;
- font-size: 16px;
- outline: none;
- transition: background-color 0.3s ease;
- width: 48%;
- /* 设置按钮宽度为48% */
- text-align: center;
- }
-
- button[type="submit"] {
- background-color: #007bff;
- color: #fff;
- }
-
- button[type="submit"]:hover {
- background-color: #0056b3;
- }
-
- .logout-button {
- background-color: #dc3545;
- color: #fff;
- text-decoration: none;
- display: inline-block;
- line-height: 1.5;
- }
-
- .logout-button:hover {
- background-color: #c82333;
- }
-
- h2 {
- margin-bottom: 10px;
- color: white;
- }
-
- h4 {
- margin-bottom: 20px;
- font-size: 14px;
- text-align: right;
- color: white;
- }
-
- .footer {
- position: fixed;
- bottom: 0;
- width: 100%;
- background-color: #d5dee7;
- padding: 10px 0;
- text-align: center;
- font-size: 14px;
- color: #6c757d;
- }
- </style>
- </head>
-
- <body>
- <div id="user-info"
- style="position: absolute; top: 10px; right: 10px; padding: 10px; background-color: #3ec83e; border: 1px solid #007bff; border-radius: 5px;">
- <span style="color: #0b0808; font-weight: bold;">你好!{{ session['username'] }}</span>
- </div>
-
- <div class="container">
- <h2>数据库信息管理系统</h2>
- <h4>——buid by 声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小桥流水78/article/detail/828860推荐阅读
相关标签
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。