python项目实战-后端个人博客系统

news2025/4/27 1:33:39

本文分享一个基于 Flask 框架开发的个人博客系统后端项目,涵盖用户注册登录、文章发布、分类管理、评论功能等核心模块。适合初学者学习和中小型博客系统开发。

一、项目结构

blog
│   app.py
│   forms.py
│   models.py
│
├───instance
│       blog.db
│
├───static
│       qu.jpg
│       styles.css
│       wc.jpg
│
├───templates
│       base.html
│       categories.html
│       category.html
│       edit_post.html
│       first.html
│       index.html
│       login.html
│       post.html
│       register.html
│       welcome.html

app.py:Flask 应用主程序,负责路由定义、请求处理和业务逻辑。
forms.py:定义所有 Web 表单类,负责用户输入验证。
models.py:定义数据库模型,映射用户、文章、分类和评论表。
instance/blog.db:SQLite 数据库文件,存储所有数据。
static/:静态资源文件夹,存放图片、CSS 样式等。
templates/:HTML 模板文件夹,使用 Jinja2 模板引擎渲染页面。

二、主要功能

1. 用户管理

  • 注册:用户通过注册表单输入用户名、邮箱和密码,密码经过哈希加密存储,保证安全。
  • 登录/登出:支持用户登录验证,登录后可访问受保护页面,登出后清除会话。
  • 用户认证:集成 Flask-Login,管理用户会话和权限。

2. 文章管理

  • 发布文章:登录用户可以创建新文章,填写标题、内容并选择分类。
  • 文章展示:首页展示所有文章列表,点击进入文章详情页查看完整内容和评论。
  • 新建文章:文章新建。

3. 分类管理

  • 分类列表:展示所有文章分类,方便用户浏览不同主题文章。
  • 分类详情:查看某个分类下的所有文章。

4. 评论功能

  • 添加评论:用户可以在文章详情页发表评论。
  • 评论展示:文章详情页显示所有评论,增强互动性。

三、运行测试

环境准备:pip install flask flask_sqlalchem  等等

启动项目:运行 python app.py 访问 http://127.0.0.1:5000/ 进入博客首页

数据库初始化:程序启动时自动创建数据库和默认分类,无需手动操作

四、code

1、python code

app.py

import logging
from flask import Flask, render_template, redirect, url_for, flash, request
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, login_user, login_required, logout_user, current_user
from werkzeug.security import generate_password_hash, check_password_hash
from models import db, User, Post, Category, Comment
from forms import RegistrationForm, LoginForm, PostForm, CategoryForm
from datetime import datetime

# 初始化日志配置
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blog.db'
db.init_app(app)

login_manager = LoginManager()
login_manager.init_app(app)

@login_manager.user_loader
def load_user(user_id):
    logger.debug(f"加载用户,ID={user_id}")
    return db.session.get(User, int(user_id))

@app.route('/')
def first():
    logger.info("访问首页 /")
    return render_template('first.html')

@app.route('/welcome')
def welcome():
    logger.info("访问欢迎页 /welcome")
    return render_template('welcome.html')

@app.route('/index')
def index():
    logger.info("访问文章列表页 /index")
    posts = Post.query.all()
    logger.info(f"查询到 {len(posts)} 篇文章")
    return render_template('index.html', posts=posts)

@app.route('/register', methods=['GET', 'POST'])
def register():
    form = RegistrationForm()
    if form.validate_on_submit():
        # 先检查邮箱是否已存在
        existing_user = User.query.filter_by(email=form.email.data).first()
        if existing_user:
            flash('该邮箱已被注册,请使用其他邮箱。', 'warning')
            logger.warning(f"注册失败,邮箱已存在: {form.email.data}")
            return render_template('register.html', form=form)

        # 也可以检查用户名是否已存在,防止重复
        existing_username = User.query.filter_by(username=form.username.data).first()
        if existing_username:
            flash('该用户名已被使用,请选择其他用户名。', 'warning')
            logger.warning(f"注册失败,用户名已存在: {form.username.data}")
            return render_template('register.html', form=form)

        hashed_password = generate_password_hash(form.password.data, method='pbkdf2:sha256')
        new_user = User(username=form.username.data, email=form.email.data, password=hashed_password)
        db.session.add(new_user)
        try:
            db.session.commit()
            flash('注册成功!', 'success')
            logger.info(f"用户注册成功,用户名: {new_user.username}, 邮箱: {new_user.email}")
            return redirect(url_for('login'))
        except IntegrityError as e:
            db.session.rollback()
            flash('注册失败,用户名或邮箱已存在。', 'danger')
            logger.error(f"数据库错误,注册失败: {e}")
            return render_template('register.html', form=form)
    elif request.method == 'POST':
        logger.warning(f"注册表单验证失败,错误: {form.errors}")
    return render_template('register.html', form=form)

@app.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        logger.info(f"登录尝试,用户名: {form.username.data}")
        user = User.query.filter_by(username=form.username.data).first()
        if user and check_password_hash(user.password, form.password.data):
            login_user(user)
            logger.info(f"用户登录成功,用户名: {user.username}")
            return redirect(url_for('welcome'))
        else:
            logger.warning("登录失败,用户名或密码错误")
            flash('登录失败,请检查用户名和密码', 'danger')
    elif request.method == 'POST':
        logger.warning(f"登录表单验证失败,错误: {form.errors}")
    return render_template('login.html', form=form)

@app.route('/logout')
@login_required
def logout():
    logger.info(f"用户登出,用户名: {current_user.username}")
    logout_user()
    return render_template('base.html')

@app.route('/post/new', methods=['GET', 'POST'])
@login_required
def new_post():
    form = PostForm()
    form.category_id.choices = [(c.id, c.name) for c in Category.query.all()]
    if form.validate_on_submit():
        logger.info(f"用户 {current_user.username} 创建新文章,标题: {form.title.data}")
        new_post = Post(title=form.title.data, content=form.content.data, category_id=form.category_id.data)
        db.session.add(new_post)
        db.session.commit()
        logger.info(f"文章创建成功,ID: {new_post.id}")
        flash('文章已创建!', 'success')
        return redirect(url_for('index'))
    elif request.method == 'POST':
        logger.warning(f"文章表单验证失败,错误: {form.errors}")
    return render_template('edit_post.html', form=form)

@app.route('/post/<int:post_id>')
def post(post_id):
    logger.info(f"访问文章详情页,文章ID: {post_id}")
    post = Post.query.get_or_404(post_id)
    comments = Comment.query.filter_by(post_id=post.id).all()
    logger.info(f"文章 {post_id} 有 {len(comments)} 条评论")
    return render_template('post.html', post=post, comments=comments)

@app.route('/post/<int:post_id>/comment', methods=['POST'])
def add_comment(post_id):
    post = Post.query.get_or_404(post_id)
    author = request.form.get('author')
    content = request.form.get('content')
    logger.info(f"新增评论,文章ID: {post_id}, 作者: {author}")
    new_comment = Comment(post_id=post.id, author=author, content=content)
    db.session.add(new_comment)
    db.session.commit()
    logger.info(f"评论添加成功,评论ID: {new_comment.id}")
    return redirect(url_for('post', post_id=post.id))

@app.route('/categories')
@login_required
def categories():
    logger.info(f"用户 {current_user.username} 访问分类列表")
    categories = Category.query.all()
    form = CategoryForm()
    return render_template('categories.html', categories=categories, form=form)

@app.route('/category/<int:category_id>')
@login_required
def category(category_id):
    logger.info(f"用户 {current_user.username} 访问分类详情,分类ID: {category_id}")
    category = Category.query.get_or_404(category_id)
    form = CategoryForm()
    return render_template('category.html', category=category, form=form)

if __name__ == '__main__':
    with app.app_context():
        db.create_all()
        if not Category.query.first():
            categories = ['开发', '测试', '人生感悟', '杂项']
            for category_name in categories:
                category = Category(name=category_name)
                db.session.add(category)
            db.session.commit()
            logger.info("初始化默认分类数据")
        logger.info("数据库表已创建或已存在。")
    app.run(debug=True)

forms.py

import logging
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, TextAreaField, SubmitField, SelectField
from wtforms.validators import DataRequired, Length

# 初始化日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

class RegistrationForm(FlaskForm):  # 注册表单
    username = StringField('用户名', validators=[DataRequired(), Length(min=2, max=150)])  # 用户名字段
    email = StringField('邮箱', validators=[DataRequired()])  # 邮箱字段
    password = PasswordField('密码', validators=[DataRequired()])  # 密码字段
    submit = SubmitField('注册')  # 提交按钮

    def validate(self, *args, **kwargs):
        rv = super().validate(*args, **kwargs)
        if not rv:
            logger.warning("RegistrationForm 验证失败")
        else:
            logger.info(f"RegistrationForm 验证成功,用户名: {self.username.data}")
        return rv

class LoginForm(FlaskForm):  # 登录表单
    username = StringField('用户名', validators=[DataRequired()])  # 用户名字段
    password = PasswordField('密码', validators=[DataRequired()])  # 密码字段
    submit = SubmitField('登录')  # 提交按钮

    def validate(self, *args, **kwargs):
        rv = super().validate(*args, **kwargs)
        if not rv:
            logger.warning("LoginForm 验证失败")
        else:
            logger.info(f"LoginForm 验证成功,用户名: {self.username.data}")
        return rv

class CategoryForm(FlaskForm):  # 分类表单
    name = StringField('分类', validators=[DataRequired(), Length(max=50)])  # 分类名称字段

    def validate(self, *args, **kwargs):
        rv = super().validate(*args, **kwargs)
        if not rv:
            logger.warning("CategoryForm 验证失败")
        else:
            logger.info(f"CategoryForm 验证成功,分类名称: {self.name.data}")
        return rv

class PostForm(FlaskForm):  # 文章表单
    title = StringField('标题', validators=[DataRequired()])  # 文章标题字段
    content = TextAreaField('内容', validators=[DataRequired()])  # 文章内容字段
    category_id = SelectField('分类', coerce=int, validators=[DataRequired()])  # 分类选择字段
    submit = SubmitField('提交')  # 提交按钮

    def validate(self, *args, **kwargs):
        rv = super().validate(*args, **kwargs)
        if not rv:
            logger.warning("PostForm 验证失败")
        else:
            logger.info(f"PostForm 验证成功,标题: {self.title.data}")
        return rv

models.py

import logging
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
from flask_login import UserMixin
#初始化日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
db = SQLAlchemy()  # 创建 SQLAlchemy 实例
class User(db.Model, UserMixin):  # 用户模型
    id = db.Column(db.Integer, primary_key=True)  # 用户 ID
    username = db.Column(db.String(150), unique=True, nullable=False)  # 用户名
    password = db.Column(db.String(150), nullable=False)  # 密码
    email = db.Column(db.String(150), unique=True, nullable=False)  # 邮箱
    def __repr__(self):
        logger.info(f"User实例被创建: {self.username}")
        return f"<User {self.username}>"
class Category(db.Model):  # 分类模型
    id = db.Column(db.Integer, primary_key=True)  # 分类 ID
    name = db.Column(db.String(100), nullable=False)  # 分类名称
    posts = db.relationship('Post', backref='category', lazy=True)  # 一对多关系,分类与文章
    def __repr__(self):
        logger.info(f"Category实例被创建: {self.name}")
        return f"<Category {self.name}>"
class Post(db.Model):  # 文章模型
    id = db.Column(db.Integer, primary_key=True)  # 文章 ID
    title = db.Column(db.String(150), nullable=False)  # 文章标题
    content = db.Column(db.Text, nullable=False)  # 文章内容
    created_at = db.Column(db.DateTime, default=datetime.now)  # 创建时间
    updated_at = db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now)  # 更新时间
    category_id = db.Column(db.Integer, db.ForeignKey('category.id'), nullable=False)  # 分类 ID
    def __repr__(self):
        logger.info(f"Post实例被创建: {self.title}")
        return f"<Post {self.title}>"
class Comment(db.Model):  # 评论模型
    id = db.Column(db.Integer, primary_key=True)  # 评论 ID
    post_id = db.Column(db.Integer, db.ForeignKey('post.id'))  # 文章 ID
    author = db.Column(db.String(100), nullable=False)  # 评论作者
    content = db.Column(db.Text, nullable=False)  # 评论内容
    created_at = db.Column(db.DateTime, default=datetime.now)  # 创建时间
    def __repr__(self):
        logger.info(f"Comment实例被创建,作者: {self.author}")
        return f"<Comment by {self.author}>"

2、static files

styles.css

/* 基本重置 */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}
/* 容器样式 */
.container {
    max-width: 800px; /* 最大宽度 */
    margin: 0 auto; /* 居中 */
    padding: 20px; /* 内边距 */
    background: white; /* 背景颜色 */
    border-radius: 8px; /* 圆角 */
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); /* 阴影效果 */
}
/* 全局样式 */
body {
    font-family: Arial, sans-serif;
    line-height: 1.6; /* 行高 */
    background-color: #f8f9fa;
    color: #343a40;
    margin: 0;
    padding: 20px;
}
/* 表单样式 */
form {
    display: flex; /* 使用 flexbox */
    flex-direction: column; /* 垂直排列 */
}
form input, form select, form textarea {
    margin-bottom: 15px; /* 下边距 */
    padding: 10px; /* 内边距 */
    border: 1px solid #ccc; /* 边框 */
    border-radius: 4px; /* 圆角 */
}
/* 导航栏样式 */
.navbar {
    margin-bottom: 30px;
}
/* 按钮样式 */
button, input[type="submit"] {
    background-color: #007bff; /* 按钮背景颜色 */
    color: white; /* 字体颜色 */
    border: none; /* 去掉边框 */
    padding: 10px; /* 内边距 */
    border-radius: 4px; /* 圆角 */
    cursor: pointer; /* 鼠标指针 */
    transition: background-color 0.3s; /* 背景颜色过渡效果 */
}
button:hover, input[type="submit"]:hover {
    background-color: #0056b3; /* 悬停时的背景颜色 */
}
/* 标题样式 */
h1, h2, h3 {
    text-align: center; /* 标题居中 */
    margin-bottom: 20px; /* 下边距 */
}
/* 消息提示样式 */
.alert {
    margin-bottom: 20px; /* 下边距 */
    padding: 15px; /* 内边距 */
    border-radius: 4px; /* 圆角 */
}
.alert-danger {
    background-color: #f8d7da; /* 错误消息背景 */
    color: #721c24; /* 错误消息字体颜色 */
}
.alert-success {
    background-color: #d4edda; /* 成功消息背景 */
    color: #155724; /* 成功消息字体颜色 */
}
/* 文章列表样式 */
.list-group-item {
    background-color: #ffffff;
    border: 1px solid #dee2e6;
    border-radius: 5px;
    margin-bottom: 10px;
    transition: background-color 0.3s;
}

.list-group-item:hover {
    background-color: #f1f1f1;
}

/* 文章标题样式 */
h1 {
    font-size: 2.0rem;
    margin-bottom: 20px;
}

/* 表单样式 */
.form-label {
    font-weight: bold;
}

.form-control {
    border-radius: 5px;
}

.btn-primary {
    background-color: #007bff;
    border: none;
    border-radius: 5px;
}

.btn-primary:hover {
    background-color: #0056b3;
}

/* 评论区样式 */
.comment-section {
    margin-top: 20px;
}

.comment-section h3 {
    margin-bottom: 15px;
}

.comment-section .list-group-item {
    background-color: #e9ecef;
}

/* 页脚样式 */
footer {
    margin-top: 30px;
    text-align: center;
    font-size: 0.9rem;
    color: #6c757d;
}
/* 链接样式 */
.nav-link {
    color: #007bff; /* 链接颜色 */
    font-size: 1.0rem;
}

.nav-link:hover {
    color: #0056b3; /* 悬停时链接颜色 */
    font-size: 3ch;
}

3、html files

base.html

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/5.1.3/css/bootstrap.min.css" -->
    <link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
    <title>个人博客</title>
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <a class="navbar-brand" href="{{ url_for('first') }}">博客首页</a>

        <div class="collapse navbar-collapse">
            <ul class="navbar-nav mr-auto">
                {% if current_user.is_authenticated %}
                    <li class="nav-item">
                       <a class="nav-link" href="{{ url_for('index') }}">我的博客</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="{{ url_for('new_post') }}">新建文章</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="{{ url_for('categories') }}">分类</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="{{ url_for('logout') }}">登出</a>
                    </li>
                {% else %}
                    <li class="nav-item">
                        <a class="nav-link" href="{{ url_for('login') }}">登录</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="{{ url_for('register') }}">注册</a>
                    </li>
                {% endif %}
            </ul>
        </div>
    </nav>
    <div class="container mt-4">
        {% with messages = get_flashed_messages(with_categories=true) %}
            {% if messages %}
                {% for category, message in messages %}
                    <div class="alert alert-{{ category }} alert-dismissible fade show">
                        {{ message }}
                        <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
                    </div>
                {% endfor %}
            {% endif %}
        {% endwith %}
        {% block content %}{% endblock %}
    </div>
</body>
</html>

categories.html

{% extends 'base.html' %}

{% block content %}
<h1>分类列表</h1>
<ul class="list-group">
    {% for category in categories %}
        <li class="list-group-item">
            <a href="{{ url_for('category', category_id=category.id) }}">{{ category.name }}</a>
            <span class="badge bg-secondary">{{ category.posts|length }} 篇文章</span>  <!-- 显示文章数量 -->
        </li>
    {% endfor %}
    <a href="{{ url_for('index') }}" class="btn btn-primary mt-4">返回首页</a>
</ul>
{% endblock %}

category.html

{% extends "base.html" %}

{% block content %}
<h1 class="mt-5">{{ category.name }} 分类</h1>
<p>以下是属于 "{{ category.name }}" 分类的文章:</p>

<div class="list-group">
    {% for post in category.posts %}
    <a href="{{ url_for('post', post_id=post.id) }}" class="list-group-item list-group-item-action">
        <h5 class="mb-1">{{ post.title }}</h5>
        <p class="mb-1">{{ post.summary }}</p>
        <small>发布于 {{ post.created_at.strftime('%Y-%m-%d') }}</small>
        <small>分类: <a href="{{ url_for('category', category_id=post.category_id) }}">{{ post.category.name }}</a></small>
    </a>
    {% else %}
    <div class="alert alert-info" role="alert">
        该分类下没有文章。
    </div>
    {% endfor %}
</div>
<a href="{{ url_for('categories') }}" class="btn btn-secondary mt-5">返回分类列表</a>
{% endblock %}

edit_post.html

{% extends 'base.html' %}

{% block content %}
<h1>新建文章</h1>
<form method="POST" action="{{ url_for('new_post') }}">
    {{ form.hidden_tag() }}
    <div class="mb-3">
        {{ form.title.label(class="form-label") }}
        {{ form.title(class="form-control") }}
    </div>
    <div class="mb-3">
        {{ form.content.label(class="form-label") }}
        {{ form.content(class="form-control", rows=5) }}
    </div>
    <div class="mb-3">
        {{ form.category_id.label(class="form-label") }}
        {{ form.category_id(class="form-select") }}
    </div>
    <button type="submit" class="btn btn-primary">提交</button>
</form>
{% endblock %}

first.html

{% extends "base.html" %}

{% block content %}
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>动态时间与图片展示</title>
    <style>

        #current-time {
            font-size: 24px;
            font-weight: bold;
            margin: 20px 0;
        }
        img {
            max-width: 100%;
            height: auto;
            margin-top: 20px;
        }
    </style>
</head>
<body>
    <h1>欢迎来到个人博客系统</h1>
    <div id="current-time"></div> <!-- 显示当前时间 -->
    
    <img src="{{ url_for('static', filename='qu.jpg') }}" alt="展示图片"> <!-- 替换为你的图片路径 -->

    <script>
        function updateTime() {
            const now = new Date();
            const options = { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false };
            document.getElementById('current-time').innerText = now.toLocaleString('zh-CN', options);
        }

        setInterval(updateTime, 1000); // 每秒更新一次时间
        updateTime(); // 页面加载时立即显示时间
    </script>
</body>
{% endblock %}

login.html

{% extends 'base.html' %}

{% block content %}
<h1>登录</h1>
<form method="POST">
    {{ form.hidden_tag() }}
    <div class="mb-3">
        {{ form.username.label(class="form-label") }}
        {{ form.username(class="form-control") }}
    </div>
    <div class="mb-3">
        {{ form.password.label(class="form-label") }}
        {{ form.password(class="form-control") }}
    </div>
    <button type="submit" class="btn btn-primary">登录</button>
</form>
{% endblock %}

index.html

{% extends 'base.html' %}
{% with messages = get_flashed_messages(with_categories=true) %}
  {% if messages %}
    <ul class="flashes">
      {% for category, message in messages %}
        <li class="{{ category }}">{{ message }}</li>
      {% endfor %}
    </ul>
  {% endif %}
{% endwith %}
{% block content %}
<h1>文章列表</h1>
<ul class="list-group">
    {% for post in posts %}
        <li class="list-group-item">
            <a href="{{ url_for('post', post_id=post.id) }}">{{ post.title }}</a>
            <small class="text-muted">创建于 {{ post.created_at.strftime('%Y-%m-%d') }}</small>
        </li>
    {% endfor %}
</ul>
{% endblock %}

post.html

{% extends 'base.html' %}

{% block content %}
<h1>{{ post.title }}</h1>
<p>{{ post.content }}</p>
<h3>评论</h3>
<form method="POST" action="{{ url_for('add_comment', post_id=post.id) }}">
    <input type="text" name="author" placeholder="你的名字" required>
    <textarea name="content" placeholder="你的评论" required></textarea>
    <button type="submit">提交评论</button>
</form>
<ul class="list-group mt-3">
    {% for comment in comments %}
        <li class="list-group-item">
            <strong>{{ comment.author }}</strong>: {{ comment.content }}
        </li>
    {% endfor %}
</ul>
{% endblock %}

register.html

{% extends 'base.html' %}

{% block content %}
<h1>注册</h1>
<form method="POST">
    {{ form.hidden_tag() }}
    <div class="mb-3">
        {{ form.username.label(class="form-label") }}
        {{ form.username(class="form-control") }}
    </div>
    <div class="mb-3">
        {{ form.email.label(class="form-label") }}
        {{ form.email(class="form-control") }}
    </div>
    <div class="mb-3">
        {{ form.password.label(class="form-label") }}
        {{ form.password(class="form-control") }}
    </div>
    <button type="submit" class="btn btn-primary">注册</button>
</form>
{% endblock %}

 welcome.html

<!-- templates/welcome.html -->
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
    <title>欢迎</title>
</head>
<body>
    <div class="container mt-4">
        <h1>欢迎, {{ current_user.username }}!</h1>
        <p>感谢您登录到个人博客系统。</p>
        <img src="{{ url_for('static', filename='wc.jpg') }}" alt="欢迎图片" style="max-width: 100%; height: auto;">
        <p><a href="{{ url_for('index') }}">我的博客</a></p>
        <p><a href="{{ url_for('first') }}">返回首页</a></p>
    </div>
</body>
</html>

五、效果展示

 

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

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

相关文章

白鲸开源与亚马逊云科技携手推动AI-Ready数据架构创新

在昨日举办的2025亚马逊云科技合作伙伴峰会圆桌论坛上&#xff0c;白鲸开源创始人兼CEO郭炜作为嘉宾&#xff0c;与亚马逊云科技及其他行业领袖共同探讨了“AI-Ready的数据架构&#xff1a;ISV如何构建面向生成式AI的强大数据基座”这一重要话题。此次论坛由亚马逊云科技大中华…

探秘LLM推理模型:hidden states中藏着的self verification的“钥匙”

推理模型在数学和逻辑推理等任务中表现出色&#xff0c;但常出现过度推理的情况。本文研究发现&#xff0c;推理模型的隐藏状态编码了答案正确性信息&#xff0c;利用这一信息可提升推理效率。想知道具体如何实现吗&#xff1f;快来一起来了解吧&#xff01; 论文标题 Reasoni…

大数据开发环境的安装,配置(Hadoop)

1. 三台linux服务器的安装 1. 安装VMware VMware虚拟机软件是一个“虚拟PC”软件&#xff0c;它使你可以在一台机器上同时运行二个或更多Windows、DOS、LINUX系统。与“多启动”系统相比&#xff0c;VMWare采用了完全不同的概念。 我们可以通过VMware来安装我们的linux虚拟机…

驱动开发硬核特训 · Day 16:字符设备驱动模型与实战注册流程

&#x1f3a5; 视频教程请关注 B 站&#xff1a;“嵌入式 Jerry” 一、为什么要学习字符设备驱动&#xff1f; 在 Linux 驱动开发中&#xff0c;字符设备&#xff08;Character Device&#xff09;驱动 是最基础也是最常见的一类驱动类型。很多设备&#xff08;如 LED、按键、…

Virtuoso ADE采用Spectre仿真中出现MOS管最小长宽比满足要求依然报错的情况解决方法

在ADE仿真中错误问题如下&#xff1a; ERROR (CMI-2440): "xxx.scs" 46338: I2.M1: The length, width, or area of the instance does not fit the given lmax-lmin, wmax-wmin, or areamax-areamin range for any model in the I2.M3.nch_hvt group. The channel w…

大模型应用开发之LLM入门

一、大模型概述 1、大模型概念 LLM是指用有大量参数的大型预训练语言模型&#xff0c;在解决各种自然语言处理任务方面表现出强大的能力&#xff0c;甚至可以展现出一些小规模语言模型所不具备的特殊能力 2、语言模型language model 语言建模旨在对词序列的生成概率进行建模…

武汉昊衡科技OLI光纤微裂纹检测仪:高密度光器件的精准守护者

随着AI技术应用越来越广&#xff0c;算力需求激增&#xff0c;光通信系统正加速向小型化、高密度、多通道方向演进。硅光芯片、高速光模块等核心器件内部的光纤通道数量成倍增加&#xff0c;波导结构愈发精细&#xff0c;传统检测手段因分辨率不足、效率低下&#xff0c;难以精…

SQL 函数进行左边自动补位fnPadLeft和FORMAT

目录 1.问题 2.解决 方式1 方式2 3.结果 1.问题 例如在SQL存储过程中&#xff0c;将1 或10 或 100 长度不足的时候&#xff0c;自动补足长度。 例如 1 → 001 10→ 010 100→100 2.解决 方式1 SELECT FORMAT (1, 000) AS FormattedNum; SELECT FORMAT(12, 000) AS Form…

Tailwind CSS实战:快速构建定制化UI的新思路

引言 在当今快节奏的前端开发环境中&#xff0c;开发者不断寻找能够提高效率并保持灵活性的工具。Tailwind CSS作为一个功能型优先的CSS框架&#xff0c;正在改变开发者构建用户界面的方式。与Bootstrap和Material UI等传统组件库不同&#xff0c;Tailwind不提供预设组件&…

【数据可视化-25】时尚零售销售数据集的机器学习可视化分析

🧑 博主简介:曾任某智慧城市类企业算法总监,目前在美国市场的物流公司从事高级算法工程师一职,深耕人工智能领域,精通python数据挖掘、可视化、机器学习等,发表过AI相关的专利并多次在AI类比赛中获奖。CSDN人工智能领域的优质创作者,提供AI相关的技术咨询、项目开发和个…

UML 活动图深度解析:以在线购物系统为例

目录 一、UML 活动图的基本构成要素 二、题目原型 三、在线购物系统用户购物活动图详细剖析 &#xff08;一&#xff09;概述 &#xff08;二&#xff09;节点分析 三、注意事项 四、活动图绘画 五、UML 活动图在软件开发中的关键价值 六、总结 在软件开发与系统设计领…

【MFC】 VS2022打开低版本的MFC,双击.rc文件,DIalog加载失败,页面弹窗fatal error RC***:cannot open*****

打开以前的MFC示例报错&#xff0c;打开VS2019的实例以及更早VS版本的实例都一样,打不开&#xff0c;还报错&#xff1b; 错误 MSB8041 此项目需要 MFC 库。从 Visual Studio 安装程序(单个组件选项卡)为正在使用的任何工具集和体系结构安装它们。 GxCameraEvents_VS2015 C:\P…

Centos9 安装 nginx 及配置

1. 安装nginx 安装依赖软件&#xff0c;安装之前可以看一下是否已经安装过以下软件&#xff0c;dnf list installed | grep zlib dnf install gcc-c dnf install zlib dnf install pcre pcre-devel dnf install openssl openssl-devel下载nginx&#xff0c;这里是下载到opt文…

使用Handsontable实现动态表格和下载表格

1.效果 2.实现代码 首先要加载Handsontable&#xff0c;在示例中我是cdn的方式引入的&#xff0c;vue的话需要下载插件 let hot null;var exportPlugin null;function showHandsontable(param) {const container document.getElementById("hot-container");// 如果…

Action:Update your application‘s configuration

在使用Maven项目时&#xff0c;有一个报错信息是&#xff1a;Update your applications configuration 这类问题&#xff0c;就是我们的application.yml文件 或者 application.properties文件 内容哪里写错了 最有可能就是对齐方式有问题

【计算机网络】IP地址

IPv4 五类地址 1.0.0.0 ~ 126.255.255.255A类子网8位&#xff0c;主机24位128.0.0.0 ~ 191.255.255.255B类子网16位&#xff0c;主机16位192.0.0.0 ~ 223.255.255.255C类子网24位&#xff0c;主机8位224.0.0.0 ~ 239.255.255.255D类不分网络地址和主机地址&#xff0c;作为组播…

Rundeck 介绍及安装:自动化调度与执行工具

Rundeck介绍 概述&#xff1a;Rundeck 是什么&#xff1f; Rundeck 是一款开源的自动化调度和任务执行工具&#xff0c;专为运维场景设计&#xff0c;帮助工程师通过统一的平台管理和执行跨系统、跨节点的任务。它由 PagerDuty 维护&#xff08;2016 年收购&#xff09;&#…

vue element使用el-table时,切换tab,table表格列项发生错位问题

展示问题 问题描述&#xff1a;使用el-table的fixed"right"属性后&#xff0c;如果切换tab时&#xff0c;回出现最后一列错误的问题 官网提供解决方法&#xff1a;doLayout 需要注意的事项&#xff1a;我这里是通过组件使用的table组件&#xff0c;涉及多层组件封装…

第十二章 Python语言-大数据分析PySpark(终)

目录 一. PySpark前言介绍 二.基础准备 三.数据输入 四.数据计算 1.数据计算-map方法 2.数据计算-flatMap算子 3.数据计算-reduceByKey方法 4.数据计算-filter方法 5.数据计算-distinct方法 6.数据计算-sortBy方法 五.数据输出 1.输出Python对象 &#xff08;1&am…

AD相同网络的铜皮和导线连接不上

出现这样的情况是不是很烦恼&#xff0c;明明是相同的网络连接不上&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f; 直接修改铜皮属性&#xff08;选择所有相同这个选项&#xff09; 这样就可以连接上了