使用Flask从0到1实现一个web blog(二)
在《使用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()
-
导入数据库相关模块和类。这里使用了SQLAlchemy作为数据库工具。
-
配置日志记录。设置日志记录的级别为DEBUG,并将日志输出到控制台。这样可以方便地查看应用程序的日志信息。
-
配置应用程序的密钥(SECRET_KEY)。这个密钥用于加密会话数据,保护用户的登录状态等信息。
-
配置数据库连接URI。这里使用了MySQL数据库,并提供了相应的用户名、密码、主机和端口等信息。
-
初始化数据库对象。将数据库对象与应用程序绑定,以便在应用程序中可以使用数据库相关功能。
-
创建用户控制器对象。这个控制器用于处理用户相关的请求和逻辑。
用户控制器(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博客的过程中,我们完成了以下主要任务:
- 初始化Flask应用程序,并配置必要的设置,如SECRET_KEY和SQLAlchemy的数据库连接。
- 创建数据库模型类(User),定义用户表的结构和字段。
- 实现数据访问对象(UserDao),提供数据库操作的方法,包括根据用户名查询用户和添加用户到数据库。
- 创建用户服务类(UserService),封装用户相关的业务逻辑,包括用户登录、注册和注销功能。
- 设计用户控制器类(UserController),注册路由和视图函数,处理用户相关的请求和页面渲染。
- 实现登录功能,接收POST请求,验证用户输入的用户名和密码,并在登录成功后将用户信息存储在session中。
- 实现注销功能,接收POST请求,从session中移除用户信息,完成用户注销操作。
- 实现主页功能,接收GET请求,根据用户登录状态展示不同的页面内容。
- 使用模板渲染机制,根据用户登录状态和相应的数据动态生成页面,如展示用户信息或显示登录表单。
- 添加日志记录功能,方便调试和追踪应用程序的运行情况。
通过上述步骤,我们建立了一个基本的MVC架构的Web博客应用程序。用户可以通过注册新账户,登录系统,并在登录状态下访问主页。我们使用了Flask的会话管理来存储用户信息,以实现认证和授权。
这个项目的实现涉及到了Flask框架的核心概念和用法,如路由注册、视图函数编写、模板渲染、数据库操作和会话管理。通过代码的模块化组织,我们实现了结构清晰、可扩展和可维护的代码。
在后续的开发中,我们可以进一步完善这个Web博客应用程序,例如添加博客文章的增删改查功能,实现评论功能和用户权限管理,以满足更多的需求和提升用户体验。
项目源码:blog_example
希望对您有所帮助谢谢!
转载自:https://juejin.cn/post/7250029035743690789