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 secrets

app = 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 secrets

app = 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 secrets

app = 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.mfbz.cn/a/888954.html

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

相关文章

Golang | Leetcode Golang题解之第457题环形数组是否存在循环

题目&#xff1a; 题解&#xff1a; func circularArrayLoop(nums []int) bool {n : len(nums)next : func(cur int) int {return ((curnums[cur])%n n) % n // 保证返回值在 [0,n) 中}for i, num : range nums {if num 0 {continue}slow, fast : i, next(i)// 判断非零且方…

docker简述

1.安装dockers&#xff0c;配置docker软件仓库 安装&#xff0c;可能需要开代理&#xff0c;这里我提前使用了下好的包安装 启动docker systemctl enable --now docker查看是否安装成功 2.简单命令 拉取镜像&#xff0c;也可以提前下载使用以下命令上传 docker load -i imag…

大数据毕业设计选题推荐-B站热门视频数据分析-Python数据可视化-Hive-Hadoop-Spark

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

使用C语言获取iostat中的await值的方法和方案

使用C语言获取iostat中的await值的方法和方案 1. 准备工作2. 调用iostat命令并获取输出3. 解析iostat输出4. 完整实现和错误处理5. 注意事项在Linux系统中,iostat命令是sysstat软件包的一部分,用于监控系统的CPU、网卡、tty设备、磁盘、CD-ROM等设备的活动情况和负载信息。其…

鸿蒙OS投票机制

(基于openharmony5.0) 投票机制 param get | grep ohos.boot.time 图 投票机制参数图 只有当所有的投票完成&#xff0c;开机动画才会退出&#xff0c;整理需要投票的系统应用&#xff08;三方应用不参与投票&#xff09;如下图所示&#xff1a; 以进程foundation为例&…

基于Kafka2.1解读Producer原理

文章目录 前言一、Kafka Producer是什么&#xff1f;二、主要组件1.Kafka Producer1.1 partitioner1.2 keySerializer1.3 valueSerializer1.4 accumulator1.5 sender 2.Sender2.1 acks2.2 clientinFlightBatches 3. Selector3.1 nioSelector3.2 channels 4. 全局总览 总结 前言…

Arduino UNO R3自学笔记20 之 Arduino如何测定电机速度?

注意&#xff1a;学习和写作过程中&#xff0c;部分资料搜集于互联网&#xff0c;如有侵权请联系删除。 前言&#xff1a;在学习了Arduino的相关基础知识后&#xff0c;现在做个综合应用&#xff0c;给旋转的电机测速。 1.实验目的 测定旋转电机的转速。 2.实验器材-编码器 …

【hot100-java】二叉树的最近公共祖先

二叉树篇 我觉得是比两个节点的深度&#xff0c;取min&#xff08;一种情况&#xff09; DFS解题。 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val x; }* }*/ clas…

力扣题11~15

题11&#xff08;中等&#xff09;&#xff1a; 思路&#xff1a; 这种题目第一眼就是双循环&#xff0c;但是肯定不行滴&#xff0c;o(n^2)这种肯定超时&#xff0c;很难接受。 所以要另辟蹊径&#xff0c;我们先用俩指针&#xff08;标志位&#xff09;在最左端和最右端&am…

基于SpringBoot智能垃圾分类系统【附源码】

基于SpringBoot智能垃圾分类系统 效果如下&#xff1a; 系统首页界面 用户注册界面 垃圾站点页面 商品兑换页面 管理员登录界面 垃圾投放界面 物业登录界面 物业功能界图 研究背景 随着城市化进程的加速&#xff0c;生活垃圾的产量急剧增加&#xff0c;传统的垃圾分类方式已…

【C++】二叉搜索树+变身 = AVL树

&#x1f680;个人主页&#xff1a;小羊 &#x1f680;所属专栏&#xff1a;C 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 前言一、AVL树二、AVL树的实现2.1 平衡因子2.2 旋转处理2.2.1 左单旋&#xff1a;插入新节点后单纯的右边高2.2.2 …

光路科技TSN交换机:驱动自动驾驶技术革新,保障高精度实时数据传输

自动驾驶技术正快速演进&#xff0c;对实时数据处理能力的需求激增。光路科技推出的TSN&#xff08;时间敏感网络&#xff09;交换机&#xff0c;在比亚迪最新车型中的成功应用&#xff0c;显著推动了这一领域的技术进步。 自动驾驶技术面临的挑战 自动驾驶系统需整合来自雷达…

大模型基础:基本概念、Prompt、RAG、Agent及多模态

随着大模型的迅猛发展&#xff0c;LLM 作为人工智能的核心力量&#xff0c;正以前所未有的方式重塑着我们的生活、学习和工作。无论是智能语音助手、自动驾驶汽车&#xff0c;还是智能决策系统&#xff0c;大模型都是幕后英雄&#xff0c;让这些看似不可思议的事情变为可能。本…

43 C 程序动态内存分配:内存区域划分、void 指针、内存分配相关函数(malloc、calloc、realloc、_msize、free)、内存泄漏

目录 1 C 程序内存区域划分 1.1 代码区 (Code Section) 1.2 全局/静态区 (Global/Static Section) 1.3 栈区 (Stack Section) 1.4 堆区 (Heap Section) 1.5 动态内存分配 2 void 指针&#xff08;无类型指针&#xff09; 2.1 void 指针介绍 2.2 void 指针的作用 2.3 …

Java基本数据类型和String类型的转换

1.基本介绍 在程序开发中&#xff0c;我们经常需要将基本数据类型转换成String类型。或者将String类型转为基本数据类型。 2.基本类型转String类型 语法&#xff1a;将 基本数据类型的值 “” 即可 3.String类型转基本数据类型 语法&#xff1a;通过基本类型的包装类调用…

【DataSophon】DataSophon1.2.1 整合Zeppelin并配置Hive|Trino|Spark解释器

目录 ​一、Zeppelin简介 二、实现步骤 2.1 Zeppelin包下载 2.2 work配置文件 三、配置常用解释器 3.1配置Hive解释器 3.2 配置trino解释器 3.3 配置Spark解释器 一、Zeppelin简介 Zeppelin是Apache基金会下的一个开源框架&#xff0c;它提供了一个数据可视化的框架&am…

浏览器动态移动的小球源码分享

浏览器动态移动的小球源码分享 <script>(function(a){var width100,height100,borderRadius100,circlefunction(){};circle.prototype{color:function(){let colour "#"Math.floor(Math.random()*255).toString(16)Math.floor(Math.random()*255).toString…

爬虫案例——爬取腾讯社招

案例需求&#xff1a; 1.爬取腾讯社招的数据&#xff08;搜索 | 腾讯招聘&#xff09;包括岗位名称链接时间公司名称 2.爬取所有页&#xff08;翻页&#xff09; 3.利用jsonpath进行数据解析 4.保存数据&#xff1a;txt文本形式和excel文件两种形式 解析&#xff1a; 1.分…

hdfs伪分布式集群搭建

1 准备 vmware 虚拟三台centos系统的节点三台机器安装好jdk环境关闭防火墙&#xff08;端口太多&#xff0c;需要的自行去开关端口&#xff09;hadoop压缩包解压至三台服务器 可在一台节点上配置完成后克隆为三台节点 2 host修改 vi /etc/hosts在每个节点上添加三台机器的i…

【Linux】Shell脚本基础+条件判断与循环控制

目录 一、介绍 1. Linux提供的Shell解析器 2. bash和sh关系 3. Centos默认的Shell解析器是bash 二、定义 1. 变量名的定义规则 2. 等号周围没有空格 3. 查看变量 4. 删除变量 5. 正确地定义数组 6. 将局部环境变量提升为全局 7. 正确选择引号 8. 特殊变量名 三…