likes
comments
collection
share

使用Flask从0到1实现一个web blog(二)

作者站长头像
站长
· 阅读数 13

《使用Flask从0到1实现一个web blog(一)》这篇文章中,我们介绍了如何使用Flask框架搭建一个MVC结构的Web博客。该文章提供了一个简要的步骤指南,让读者可以从头开始构建一个完整的Web应用程序。

首先,我们通过安装Flask和相关依赖项来准备环境。接着,我们创建了项目的目录结构,包括app、app/views、app/services、app/dao、app/models、app/templates和app/static等子目录。这种模块化的结构有助于代码的组织和维护。

我们创建了一个Flask应用程序对象,并设置了应用程序的密钥,用于会话管理。然后,我们定义了模型类、数据访问对象类和服务类,分别处理数据模型、数据访问和业务逻辑。通过这种方式,我们实现了对用户数据的存储、查询和操作功能。

在控制器类中,我们注册了路由,并定义了相应的处理函数。这些处理函数负责接收和处理用户的请求,调用相应的服务类方法,并返回相应的视图或结果。这样,我们就实现了用户登录、注销和注册等功能。

最后,我们创建了HTML模板和样式文件,用于渲染和呈现前端页面。这样,用户可以在浏览器中以友好的界面进行操作和交互。

接下我们一起来完善这个例子:

app.py的完善:

from flask import Flask,session,redirect,url_for
from flask_sqlalchemy import SQLAlchemy
import mysql.connector
import logging

from app.views.user_controller import UserController
from app.database.database import db



app = Flask(__name__)

# 配置日志记录
app.logger.setLevel(logging.DEBUG)
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
stream_handler.setFormatter(formatter)
app.logger.addHandler(stream_handler)

app.debug=True
app.config['SECRET_KEY'] = '1234567890.'
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+mysqlconnector://root:123456@localhost:3306/myblog'



# db = SQLAlchemy(app)
db.init_app(app)

user_controller=UserController(app)

if __name__=='__main__':
    app.run()
  1. 导入数据库相关模块和类。这里使用了SQLAlchemy作为数据库工具。

  2. 配置日志记录。设置日志记录的级别为DEBUG,并将日志输出到控制台。这样可以方便地查看应用程序的日志信息。

  3. 配置应用程序的密钥(SECRET_KEY)。这个密钥用于加密会话数据,保护用户的登录状态等信息。

  4. 配置数据库连接URI。这里使用了MySQL数据库,并提供了相应的用户名、密码、主机和端口等信息。

  5. 初始化数据库对象。将数据库对象与应用程序绑定,以便在应用程序中可以使用数据库相关功能。

  6. 创建用户控制器对象。这个控制器用于处理用户相关的请求和逻辑。

用户控制器(UserController)用于处理与用户相关的请求和逻辑:

app/view/user_controller.py

import json
from flask import flash, render_template, request, redirect, url_for, session, current_app
from app.services.user_service import UserService

class UserController:
    def __init__(self,app):
        self.app=app
        self.user_service=UserService()
        #路由注册
        self.app.add_url_rule('/',view_func=self.index)
        
        self.app.add_url_rule('/login',view_func=self.login,methods=['GET','POST'])
        self.app.add_url_rule('/logout',view_func=self.logout,methods=['GET','POST'])
        
    def index(self):
        if 'user' in session:
            user=json.loads(session['user'])
            current_app.logger.debug("user={}".format(user))
            return render_template('index.html',user=user)
        return render_template('login.html')
    
    def login(self):
        if request.method=='POST':
            username=request.form['username']
            password=request.form['password']
            # current_app.logger.debug("username={}".format(username))
            # current_app.logger.debug("password={}".format(password))
            user=self.user_service.login(username,password)
            current_app.logger.debug("password={}".format(json.dumps(user.to_json()))) 
            if user:
                session['user']=json.dumps(user.to_json())
                return redirect(url_for('index'))
            else:
                #用户登录失败,显示错误信息
                error='Invalid username or password'
                current_app.logger.debug("error={}".format(error))
                flash(error)
                return render_template('login.html',error=error)
            
        return render_template('login.html')
    
    def logout(self):
        if request.method=='POST':
            self.user_service.logout()
            return redirect(url_for('index'))
        return render_template('login.html')

    def register(self):
        if request.method == 'POST':
            username = request.form['username']
            password = request.form['password']
            result=self.user_service.register(username=username, password=password)
            if result:
                # 注册成功,重定向到登录页面
                flash('注册成功,请登录')
                return redirect(url_for('login'))  # 假设登录路由为 'login'
            else:
                # 注册失败,显示错误提示
                flash('注册失败,请重试')
        return render_template('register.html')  # 假设注册页面为 'register.html'

用户服务类(UserService),用于处理与用户数据和逻辑相关的操作: app/service/user_service.py


from flask import session
from app.dao.user_dao import UserDao
from app.models.user import User
# 

class UserService:
    def __init__(self):
        self.user_dao=UserDao()
        
    def login(self,username,password):
        user=self.user_dao.get_user_by_username(username)
        if user and user.password==password:
            return user
        else:
            return None   
    def logout(self):
        session.pop('user',None)
    
    def register(self,username,password): 
        user=self.user_dao.get_user_by_username(username)
        if user:
            return None 
        new_user=User(username=username,password=password)
        self.user_dao.add_user(new_user)
    
        return new_user

UserService通过与用户数据访问对象(UserDao)的交互,提供了登录、注销和注册用户的功能。用户服务类将用户相关的数据操作封装起来,供控制器(UserController)使用。

用户数据访问对象(UserDao),用于与数据库进行交互,执行用户相关的数据操作: app/dao/user_dao.py

from app.database.database import db
from app.models.user import User

class UserDao: 
    
    def get_user_by_username(self,username):
        #查询数据库获取用户信息
        return User.query.filter_by(username=username).first()


    def add_user(self,user):
        db.session.add(user)
        db.session.commit()

通过与数据库交互,实现了获取用户信息和添加用户的功能。用户数据访问对象封装了与数据库的具体操作,供用户服务类(UserService)调用,实现了对用户数据的持久化操作。

app/models/user.py

from app.database.database import db

class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(50), unique=True, nullable=False)
    password = db.Column(db.String(100), nullable=False)
    
    def __init__(self,username, password):
        
        self.username = username
        self.password = password
        
    def __repr__(self):
        return '<User %r>' % self.username
    def to_json(self):
        return {
            'id': self.id,
            'username': self.username,
            'password': self.password
        }

用户模型类,并指定了其在数据库中的结构。它提供了属性访问、初始化、字符串表示和转换为JSON格式的功能,方便对用户对象进行操作和序列化

app/templates/login.html

<!-- login.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Login</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
</head>
<body>
    <div class="login-container">
        <div class="login-card">
          <h1>Login</h1>
          <form method="POST" action="{{ url_for('login') }}">
            <input type="text" name="username" placeholder="Username">
            <input type="password" name="password" placeholder="Password">
            <input type="submit" value="Login">
          </form>
        </div>
      </div>
</body>
</html>
.login-container {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
  }
  
  .login-card {
    width: 300px;
    padding: 20px;
    background-color: #f8f8f8;
    border-radius: 5px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    text-align: center;
  }
  
  .login-card h1 {
    margin-bottom: 20px;
  }
  
  .login-card input[type="text"],
  .login-card input[type="password"] {
    width: 90%;
    padding: 10px;
    margin-bottom: 10px;
    border: 1px solid #ccc;
    border-radius: 4px;
    text-align: center;
    
  }
  
  .login-card input[type="submit"] {
    width: 100%;
    padding: 10px;
    background-color: #4CAF50;
    color: #fff;
    border: none;
    border-radius: 4px;
    cursor: pointer;
  }
  
  .login-card input[type="submit"]:hover {
    background-color: #45a049;
  }

app/templates/index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Blog Home</title>
        <link rel="stylesheet" href="{{ url_for('static', filename='index.css') }}">
    </head>
    
<body>
    <div class="header">
        
        <form action="/logout" method="post">
            <button class="logout-button" type="submit">Logout</button>
        </form>
    </div>
    <div class="container">
        <div class="sidebar">
            <h2>Hot Articles</h2>
            <ul>
                <li>Article 1</li>
                <li>Article 2</li>
                <li>Article 3</li>
                <!-- Add more hot articles here -->
            </ul>
        </div>
        <div class="content">
            <h2>Article Title</h2>
            <p>Article content goes here...</p>
        </div>
        <div class="info">
            <h2>My Info</h2>
            <p>Id:{{user.id}}</p>
            <p>Name: {{user.username}}</p>
            <p>Email: john.doe@example.com</p>
            <p>Location: City, Country</p>
        </div>
    </div>
    
</body>
</html>
body {
  margin: 0;
  padding: 20px;
  font-family: Arial, sans-serif;
  height: 100%;

}
.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}
.header h1 {
  margin: 0;
}
.logout-button {
  background-color: #ff5f5f;
  color: #fff;
  padding: 10px 15px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
.logout-button:hover {
  background-color: #ff3b3b;
}
.red {
  color: #ff5f5f;
}

.container {
  display: flex;
  height: 100vh; /* 让容器占满整个屏幕高度 */
}

.sidebar, .content, .info {
  flex-grow: 1;
  background-color: #f5f5f5; /* 设置背景颜色为灰色 */
}
.content {
  width: 60%;
}

.sidebar {
  width: 20%;
  margin-right: 10px;
}

.info {
  width: 20%;
  margin-left: 10px;
}

我们来看一下运行的效果:

使用Flask从0到1实现一个web blog(二)

使用Flask从0到1实现一个web blog(二)

在使用Flask从0到1实现一个Web博客的过程中,我们完成了以下主要任务:

  1. 初始化Flask应用程序,并配置必要的设置,如SECRET_KEY和SQLAlchemy的数据库连接。
  2. 创建数据库模型类(User),定义用户表的结构和字段。
  3. 实现数据访问对象(UserDao),提供数据库操作的方法,包括根据用户名查询用户和添加用户到数据库。
  4. 创建用户服务类(UserService),封装用户相关的业务逻辑,包括用户登录、注册和注销功能。
  5. 设计用户控制器类(UserController),注册路由和视图函数,处理用户相关的请求和页面渲染。
  6. 实现登录功能,接收POST请求,验证用户输入的用户名和密码,并在登录成功后将用户信息存储在session中。
  7. 实现注销功能,接收POST请求,从session中移除用户信息,完成用户注销操作。
  8. 实现主页功能,接收GET请求,根据用户登录状态展示不同的页面内容。
  9. 使用模板渲染机制,根据用户登录状态和相应的数据动态生成页面,如展示用户信息或显示登录表单。
  10. 添加日志记录功能,方便调试和追踪应用程序的运行情况。

通过上述步骤,我们建立了一个基本的MVC架构的Web博客应用程序。用户可以通过注册新账户,登录系统,并在登录状态下访问主页。我们使用了Flask的会话管理来存储用户信息,以实现认证和授权。

这个项目的实现涉及到了Flask框架的核心概念和用法,如路由注册、视图函数编写、模板渲染、数据库操作和会话管理。通过代码的模块化组织,我们实现了结构清晰、可扩展和可维护的代码。

在后续的开发中,我们可以进一步完善这个Web博客应用程序,例如添加博客文章的增删改查功能,实现评论功能和用户权限管理,以满足更多的需求和提升用户体验。

项目源码:blog_example

希望对您有所帮助谢谢!