MySQL(SQLite3)数据库+Flask框架+HTML搭建个人博客网站

        搭建一个博客并实现文章的发送功能,涉及到前后端开发和数据库操作。以下是一个简单的示例,使用Python的Flask框架作为后端,HTML和JavaScript作为前端,SQLite作为数据库。

1. 项目结构

my_blog/
│
├── app.py
├── templates/
│   ├── index.html
│   ├── profile.html
│   └── base.html
├── static/
│   ├── style.css
│   └── script.js
└── blog.db

2. 后端代码 (app.py)

以下数据库使用的是sqlite3(后文介绍MySQL数据库和数组的实现):
from flask import Flask, render_template, request, redirect, url_for, session
import sqlite3
import secretsapp = Flask(__name__)
app.secret_key = secrets.token_hex(16)  # 生成一个 32 字节的随机十六进制字符串# 初始化数据库
def init_db():db = sqlite3.connect('blog.db')cursor = db.cursor()cursor.execute('''CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT,username TEXT NOT NULL,password TEXT NOT NULL)''')cursor.execute('''CREATE TABLE IF NOT EXISTS posts (id INTEGER PRIMARY KEY AUTOINCREMENT,user_id INTEGER NOT NULL,title TEXT NOT NULL,content TEXT NOT NULL,FOREIGN KEY (user_id) REFERENCES users(id))''')db.commit()db.close()init_db()@app.route('/')
def index():db = sqlite3.connect('blog.db')cursor = db.cursor()cursor.execute('SELECT * FROM posts')posts = cursor.fetchall()db.close()return render_template('index.html', posts=posts)@app.route('/profile', methods=['GET', 'POST'])
def profile():if 'username' not in session:return redirect(url_for('index'))if request.method == 'POST':title = request.form['title']content = request.form['content']db = sqlite3.connect('blog.db')cursor = db.cursor()cursor.execute('INSERT INTO posts (user_id, title, content) VALUES (?, ?, ?)', (session['user_id'], title, content))db.commit()db.close()return redirect(url_for('profile'))db = sqlite3.connect('blog.db')cursor = db.cursor()cursor.execute('SELECT * FROM posts WHERE user_id = ?', (session['user_id'],))posts = cursor.fetchall()db.close()return render_template('profile.html', posts=posts)@app.route('/login', methods=['GET', 'POST'])
def login():if request.method == 'POST':username = request.form['username']password = request.form['password']db = sqlite3.connect('blog.db')cursor = db.cursor()cursor.execute('SELECT * FROM users WHERE username = ? AND password = ?', (username, password))user = cursor.fetchone()db.close()if user:session['username'] = user[1]session['user_id'] = user[0]return redirect(url_for('profile'))else:return "Invalid credentials"return render_template('login.html')@app.route('/logout')
def logout():session.pop('username', None)session.pop('user_id', None)return redirect(url_for('index'))if __name__ == '__main__':app.run(debug=True)
 如果使用的是MySQL数据库,请注意:

        使用MySQL作为数据库时,需要对代码进行一些调整。首先,确保你已经安装了所需的Python库:

pip install Flask mysql-connector-python

并将app.py文件的内容用以下代码代替 

from flask import Flask, render_template, request, redirect, url_for, session
import mysql.connector
import secretsapp = Flask(__name__)
app.secret_key = secrets.token_hex(16)  # 生成一个 32 字节的随机十六进制字符串# MySQL database configuration
db_config = {'host': 'localhost','user': 'your_username','password': 'your_password','database': 'your_database'
}# Database initialization
def init_db():db = mysql.connector.connect(**db_config)cursor = db.cursor()cursor.execute('''CREATE TABLE IF NOT EXISTS users (id INT AUTO_INCREMENT PRIMARY KEY,username VARCHAR(255) NOT NULL,password VARCHAR(255) NOT NULL)''')cursor.execute('''CREATE TABLE IF NOT EXISTS posts (id INT AUTO_INCREMENT PRIMARY KEY,user_id INT NOT NULL,title VARCHAR(255) NOT NULL,content TEXT NOT NULL,FOREIGN KEY (user_id) REFERENCES users(id))''')db.commit()db.close()init_db()@app.route('/')
def index():db = mysql.connector.connect(**db_config)cursor = db.cursor()cursor.execute('SELECT * FROM posts')posts = cursor.fetchall()db.close()return render_template('index.html', posts=posts)@app.route('/profile', methods=['GET', 'POST'])
def profile():if 'username' not in session:return redirect(url_for('index'))if request.method == 'POST':title = request.form['title']content = request.form['content']db = mysql.connector.connect(**db_config)cursor = db.cursor()cursor.execute('INSERT INTO posts (user_id, title, content) VALUES (%s, %s, %s)', (session['user_id'], title, content))db.commit()db.close()return redirect(url_for('profile'))db = mysql.connector.connect(**db_config)cursor = db.cursor()cursor.execute('SELECT * FROM posts WHERE user_id = %s', (session['user_id'],))posts = cursor.fetchall()db.close()return render_template('profile.html', posts=posts)@app.route('/login', methods=['GET', 'POST'])
def login():if request.method == 'POST':username = request.form['username']password = request.form['password']db = mysql.connector.connect(**db_config)cursor = db.cursor()cursor.execute('SELECT * FROM users WHERE username = %s AND password = %s', (username, password))user = cursor.fetchone()db.close()if user:session['username'] = user[1]session['user_id'] = user[0]return redirect(url_for('profile'))else:return "Invalid credentials"return render_template('login.html')@app.route('/logout')
def logout():session.pop('username', None)session.pop('user_id', None)return redirect(url_for('index'))if __name__ == '__main__':app.run(debug=True)
当然也可以不使用数据库,而用数组储存模拟的数据:

我们用posts数组来存储我们模拟的数据,请将以下代码写入app.py文件

from flask import Flask, render_template, session, redirect, url_for, request
import secretsapp = Flask(__name__)
app.secret_key = secrets.token_hex(16)  # 生成一个 32 字节的随机十六进制字符串# 模拟数据
posts = [(1, 'Author 1', 'First Post', 'This is the content for the first post.'),(2, 'Author 2', 'Second Post', 'This is the content for the second post.'),
]# 主页
@app.route('/')
def index():return render_template('index.html', posts=posts)# 登录视图(示例用简单的登录方式)
@app.route('/login', methods=['GET', 'POST'])
def login():if request.method == 'POST':session['username'] = request.form.get('username')return redirect(url_for('index'))return render_template('login.html')# 个人中心
@app.route('/profile', methods=['GET', 'POST'])
def profile():if 'username' not in session:return redirect(url_for('login'))if request.method == 'POST':title = request.form.get('title')content = request.form.get('content')# 在此处可以添加代码将新帖子保存到数据库或列表中posts.append((len(posts) + 1, session['username'], title, content))return render_template('profile.html', posts=posts)# 登出视图
@app.route('/logout')
def logout():session.pop('username', None)return redirect(url_for('index'))if __name__ == '__main__':app.run(debug=True)
  • 设置密钥secret_key 是用于加密 Flask 应用中的某些数据的一个字符串,特别是与用户会话相关的数据。Flask 使用这个密钥来进行数据签名(比如处理 Flask 的 session 对象时)。
  • 用户会话保护:该密钥有助于防止伪造用户会话。使用时,Flask 会对存储在会话中的数据进行签名,以防止攻击者修改会话内容。

        你并不需要知道这个密钥的具体值 ,但你有方法可以获取这个随机生成的密钥,感兴趣自己多了解了解。

3. 前端代码

基础模板 (templates/base.html)
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>{% block title %}My Blog{% endblock %}</title><link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body><nav><a href="{{ url_for('index') }}">Home</a>{% if 'username' in session %}<a href="{{ url_for('profile') }}">Profile</a><a href="{{ url_for('logout') }}">Logout</a>{% else %}<a href="{{ url_for('login') }}">Login</a>{% endif %}</nav><div class="content">{% block content %}{% endblock %}</div>
</body>
</html>

首页 (templates/index.html)
{% extends "base.html" %}{% block title %}Home{% endblock %}{% block content %}
<h1>Welcome to My Blog</h1>
<ul>{% for post in posts %}<li><h2>{{ post[2] }}</h2><p>{{ post[3] }}</p></li>{% endfor %}
</ul>
{% endblock %}

        这段代码是一个使用 Jinja2 模板引擎的 HTML 模板文件。它继承了一个名为 base.html 的基础模板,并在其中定义了两个块(title 和 content)。以下是代码的详细解释:

1. {% extends "base.html" %}

  • 作用: 这行代码表示当前模板继承自 base.html 文件。base.html 通常是一个包含网站通用结构的基础模板,比如头部、导航栏、页脚等。
  • 继承: 通过继承,当前模板可以使用 base.html 中定义的结构,并在特定位置插入自己的内容。

2. {% block title %}Home{% endblock %}

  • 作用: 这行代码定义了一个名为 title 的块,并将其内容设置为 Home
  • 用途: 通常,title 块用于定义页面的标题,这个标题会显示在浏览器的标签栏中。

3. {% block content %} 和 {% endblock %}

  • 作用: 这行代码定义了一个名为 content 的块,并在其中插入了页面的主要内容。
  • 用途content 块通常用于放置页面的主要内容,比如文章列表、表单等。

4. <h1>Welcome to My Blog</h1>

  • 作用: 这是一个一级标题,显示在页面的主要内容区域。

5. <ul> 和 {% for post in posts %}

  • 作用: 这是一个无序列表,用于显示文章列表。{% for post in posts %} 是一个循环语句,遍历 posts 列表中的每一项。
  • 用途: 在循环中,每一项 post 都会生成一个列表项 <li>,并显示文章的标题和内容。

6. {{ post[2] }} 和 {{ post[3] }}

  • 作用: 这些是变量插值,用于显示 post 对象的特定属性。
    • post[2] 通常表示文章的标题。
    • post[3] 通常表示文章的内容。
个人中心 (templates/profile.html)
{% extends "base.html" %}{% block title %}Profile{% endblock %}{% block content %}
<h1>Welcome, {{ session['username'] }}!</h1>
<form action="{{ url_for('profile') }}" method="post"><label for="title">Title:</label><input type="text" id="title" name="title" required><label for="content">Content:</label><textarea id="content" name="content" required></textarea><button type="submit">Post</button>
</form>
<ul>{% for post in posts %}<li><h2>{{ post[2] }}</h2><p>{{ post[3] }}</p></li>{% endfor %}
</ul>
{% endblock %}

4. 静态文件 (static/style.css)

body {font-family: Arial, sans-serif;margin: 0;padding: 0;background-color: #f4f4f4;
}nav {background-color: #333;overflow: hidden;
}nav a {float: left;display: block;color: #f2f2f2;text-align: center;padding: 14px 16px;text-decoration: none;
}nav a:hover {background-color: #ddd;color: black;
}.content {padding: 20px;margin: 20px;
}form {margin-bottom: 20px;
}label {display: block;margin-bottom: 5px;
}input, textarea {width: 100%;padding: 8px;margin-bottom: 10px;box-sizing: border-box;
}button {padding: 10px 20px;background-color: #333;color: white;border: none;cursor: pointer;
}button:hover {background-color: #555;
}

        我暂时还没有编写login和logout的html文件,如果感兴趣可以自己先编写。不过在首页你可以直接点击profile进入个人中心,这并不影响。至于如何运行flask项目,可以在终端使用以下代码。

flask --app app run --host=0.0.0.0

5. 运行应用

  1. 确保你已经安装了Flask。如果没有,可以通过pip install flask安装。
  2. 运行app.py,访问http://127.0.0.1:5000即可看到博客首页。
  3. 登录后可以进入个人中心,发表文章。

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

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

相关文章

小赢卡贷公益行:乡村振兴与多元公益并进

在金融科技的浪潮中&#xff0c;小赢卡贷不仅以其创新的金融产品和服务赢得了市场的广泛认可&#xff0c;更以其背后的公益之心&#xff0c;积极履行社会责任&#xff0c;传递着温暖与希望。小赢公益基金会&#xff0c;作为小赢卡贷社会责任的延伸&#xff0c;主要聚焦于乡村振…

衡石分析平台系统管理手册-智能运维之系统设置

系统设置​ HENGSHI 系统设置中展示了系统运行时的一些参数&#xff0c;包括主程序相关信息&#xff0c;Base URL、HTTP 代理、图表数据缓存周期、数据集缓存大小、租户引擎等相关信息。 主程序​ 系统设置中展示了主程序相关信息&#xff0c;这些信息是系统自动生成的&#…

springboot宿舍管理-计算机毕业设计源码40740

摘要 宿舍管理系统作为一种利用信息技术改善学生住宿管理的工具&#xff0c;在大学宿舍管理中具有重要的实际意义。本文通过对国内外研究现状的调查和总结&#xff0c;探讨了宿舍管理系统的论文主题、研究背景、研究目的、研究意义以及主要研究内容。 首先&#xff0c;宿舍管理…

心觉:购物选择困难症! 为什么你总是挑不出“最完美”的商品?

Hi&#xff0c;我是心觉&#xff0c;与你一起玩转潜意识、脑波音乐和吸引力法则&#xff0c;轻松掌控自己的人生&#xff01; 挑战每日一省写作194/1000天 你有没有遇到过这样一种情况&#xff1a;打算买一款新的电子产品、家具或者衣服 但在网上和实体店翻来覆去&#xff0…

编译链接的过程发生了什么?

一&#xff1a;程序的翻译环境和执行环境 在 ANSI C 的任何一种实现中&#xff0c;存在两个不同的环境。 第 1 种是翻译环境&#xff0c;在这个环境中源代码被转换为可执行的机器指令。 第 2 种是执行环境&#xff0c;它用于实际执行代码 也就是说&#xff1a;↓ 1&#xff1…

ai免费写论文是原创吗?分享5款ai写作免费一键生成助手

在当今的学术研究和写作领域&#xff0c;AI技术的应用越来越广泛&#xff0c;尤其是在论文写作方面。许多AI写作工具声称能够一键生成高质量的论文&#xff0c;并且保证原创性。然而&#xff0c;这些工具是否真的能生成完全原创的论文&#xff0c;仍然是一个值得探讨的问题。 …

【动态规划-最长递增子序列(LIS)】【hard】力扣1671. 得到山形数组的最少删除次数

我们定义 arr 是 山形数组 当且仅当它满足&#xff1a; arr.length > 3 存在某个下标 i &#xff08;从 0 开始&#xff09; 满足 0 < i < arr.length - 1 且&#xff1a; arr[0] < arr[1] < … < arr[i - 1] < arr[i] arr[i] > arr[i 1] > … &g…

掌握甘特图,没有Excel也能轻松制作的技巧

甘特图是项目管理中常用工具&#xff0c;由亨利甘特发明。不擅长Excel者可用ZohoProjects等软件创建甘特图&#xff0c;其直观展示项目时间和任务&#xff0c;支持实时协作、工时管理等功能&#xff0c;广泛应用于各领域项目管理。 一、甘特图的由来 甘特图最初是由工程师和管…

tp5 fastadmin列表页图片批量压缩并下载

记录&#xff1a;tp5 fastadmin对列表页选中数据的多张图片进行压缩并下载。 html代码 <a href"javascript:;" class"btn btn-info btn-apple btn-disabled disabled {:$auth->check(zhuanli/zhuanli/xiazai)?:hide}" title"批量下载专利证书…

selenium-Alert类用于操作提示框/确认弹框(4)

之前文章我们提到&#xff0c;在webdriver.WebDriver类有一个switch_to方法&#xff0c;通过switch_to.alert()可以返回Alert对象&#xff0c;而Alert对象主要用于网页中弹出的提示框/确认框/文本输入框的确认或者取消等动作。 Alert介绍 当在页面定位到提示框/确认框/文本录入…

如何通过systemed实现Linux脚本在服务器的开机自启动,解决网络摄像机IPC通过 域名接入视频监控平台出现离线的问题。

目录 一.问题描述和分析 二.实现脚本开机自启动的过程 2.1确认该系统是不是systemed系统 2.2创建并配置该脚本的systemd服务 2.2.1创建服务 2.2.2配置服务 2.3启动服务 三.问题解决结果 3.1查看服务状态 3.2查看摄像机在线状态 3.3查看视频是否正常 一.问题描述和分…

leetcode:反转字符串中的单词III

题目链接 string reverse(string s1) {string s2;string::reverse_iterator rit s1.rbegin();while (rit ! s1.rend()){s2 *rit;rit;}return s2; } class Solution { public:string reverseWords(string s) {string s1; int i 0; int j 0; int length s.length(); for (i …

C++关于树的基础知识

首先区分概念 “度为m的树”指的是至少有一个结点的度是m&#xff0c;一定是非空树 “m叉树”指的是允许所有的结点都小于m&#xff0c;且可以是空树 常见考点&#xff1a; 度为m的树的第i层最多有个结点 &#xff08;对于m叉树也相同&#xff09; 第一层m的0次方 第二层m的…

电池大师 2.3.9 | 专业电池管理,延长寿命优化性能

Battery Guru 显示电池使用情况信息&#xff0c;测量电池容量&#xff08;mAh&#xff09;&#xff0c;并通过有用技巧帮助用户改变充电习惯&#xff0c;延长电池寿命。支持显示电池健康状况&#xff0c;优化电池性能。 大小&#xff1a;9.6M 百度网盘&#xff1a;https://pan…

多模态大语言模型(MLLM)-InstructBlip深度解读

前言 InstructBlip可以理解为Blip2的升级版&#xff0c;重点加强了图文对话的能力。 模型结构和Blip2没差别&#xff0c;主要在数据集收集、数据集配比、指令微调等方面下文章。 创新点 数据集收集&#xff1a; 将26个公开数据集转换为指令微调格式&#xff0c;并将它们归类…

创建osd加入集群

故障原因&#xff1a;ceph节点一个磁盘损坏&#xff0c;其中osd69 down了&#xff0c;需要更换磁盘并重新创建osd加入ceph集群。 信息采集&#xff1a; 更换磁盘前&#xff0c;查询osd69对应的盘符&#xff1a; 将对应的故障磁盘更换后&#xff0c;并重做raid&#xff0c;然后查…

≌图概念凸显有长度不同的射线

黄小宁 【摘要】自有射线概念后的2300年里一直无人能知有长度不同的射线、无人能知有互不≌的射线&#xff0c;从而使数学一直有几何“常识”&#xff1a;任何射线都没有长度差别。保距变换和≌图概念使人能一下子看到有长度不同的射线。 变量x所取各数也均由x代表&#xff0c…

1. Keepalived概念和作用

1.keepalived概念 (1)解决单点故障(组件免费) (2)可以实现高可用HA机制 (3)基于VRR协议(虚拟路由沉余协议) 2.keepalived双机主备原理

DockerCompose 启动 open-match

背景介绍 open-match是Google和unity联合开源的支持实时多人匹配的框架&#xff0c;已有多家游戏厂商在生产环境使用&#xff0c;官网 https://open-match.dev/site/ 。原本我们使用的是UOS上提供的匹配能力&#xff0c;但是UOS目前不支持自建的Dedicated servers 集群&#x…

ai论文写作软件哪个好?分享5款ai论文题目生成器

在当前的学术研究和写作领域&#xff0c;AI论文写作软件已经成为提高效率和质量的重要工具。根据多个来源的评测和推荐&#xff0c;以下是五款值得推荐的AI论文写作软件&#xff0c;其中特别推荐千笔-AIPassPaper。 1. 千笔-AIPassPaper 千笔-AIPassPaper是一款基于深度学习和…