IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> Flask实战----做了一个简易版CSDN -> 正文阅读

[Python知识库]Flask实战----做了一个简易版CSDN

数据库设计


创建数据表

需要创建两个数据表

  • users:`用户表,用于存储用户信息
  • articles:博客表,用于存储博客信息

下面以创建users为例:

//如果存在重名的将其删去
DROP TABLE IF EXISTS `articles`;
CREATE TABLE `articles` (
  `id` int NOT NULL AUTO_INCREMENT,
  `title` varchar(255) DEFAULT NULL,
  `content` text,
  `author` varchar(255) DEFAULT NULL,
  `create_date` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
  • drop table if exists:一般drop table if exists是数据库里面的,后面接表名如:drop table if exists xxx_book意思就是:如果数据库中存在xxx_book表,就把它从数据库中drop掉。备份sql中一般都有这样的语句,如果是数据库中有这个表,先drop掉,然后create表,然后再进行数据插入。
  • AUTO_INCREMENT:代表值自动增加,只有主键可以添加
  • ENGINE=InnoDB:使用baiinnobd引擎。
  • CHARSET=utf8:数据库默认编码格式为utf8.

### MySQL基本操作

MySQL基本操作

创建数据库操作类

为了复用代码,以及使用的安全性,我们一般会创建一个`myspl_util.py`文件,文件中包含一个`MysqlUtil`类。
import pymysql   # 引入pymysql模块
import traceback # 引入python中的traceback模块,跟踪错误
import sys       # 引入sys模块

class MysqlUtil():
    def __init__(self):
         # 初始化方法,连接数据库
        host = 'localhost'    # 主机名
        user = 'root'         # 数据库用户名
        password = '******'     # 数据库密码
        database = 'notebook' # 数据库名称
        self.db = pymysql.connect(host=host,user=user,password=password,db=database) # 建立连接
        self.cursor = self.db.cursor(cursor=pymysql.cursors.DictCursor) # 设置游标,并将游标设置为字典类型

    def insert(self, sql):
        '''
            插入数据库
            sql:插入数据库的sql语句
        '''
        try:
            # 执行sql语句
            self.cursor.execute(sql)
            # 提交到数据库执行
            self.db.commit()
        except Exception:  # 方法一:捕获所有异常
            # 如果发生异常,则回滚
            print("发生异常", Exception)
            self.db.rollback()
        finally:
            # 最终关闭数据库连接
            self.db.close()

    def fetchone(self, sql):
        '''
            查询数据库:单个结果集
            fetchone(): 该方法获取下一个查询结果集。结果集是一个对象
        '''
        try:
            # 执行sql语句
            self.cursor.execute(sql)
            result = self.cursor.fetchone()
        except:  # 方法二:采用traceback模块查看异常
            # 输出异常信息
            traceback.print_exc()
            # 如果发生异常,则回滚
            self.db.rollback()
        finally:
            # 最终关闭数据库连接
            self.db.close()
        return result

    def fetchall(self, sql):
        '''
            查询数据库:多个结果集
            fetchall(): 接收全部的返回结果行.
        '''
        try:
            # 执行sql语句
            self.cursor.execute(sql)
            results = self.cursor.fetchall()
        except:  # 方法三:采用sys模块回溯最后的异常
            # 输出异常信息
            info = sys.exc_info()
            print(info[0], ":", info[1])
            # 如果发生异常,则回滚
            self.db.rollback()
        finally:
            # 最终关闭数据库连接
            self.db.close()
        return results

    def delete(self, sql):
        '''
            删除结果集
        '''
        try:
            # 执行sql语句
            self.cursor.execute(sql)
            self.db.commit()
        except:  # 把这些异常保存到一个日志文件中,来分析这些异常
            # 将错误日志输入到目录文件中
            f = open("\log.txt", 'a')
            traceback.print_exc(file=f)
            f.flush()
            f.close()
            # 如果发生异常,则回滚
            self.db.rollback()
        finally:
            # 最终关闭数据库连接
            self.db.close()

 #以下省略更新功能

  • traceback.print_exc(): 将错误信息在终端输出
  • traceback.print_exc(file=f):可以将错误打印在文本中,f为文件类对象。
  • flush():flush() 方法是用来刷新缓冲区的,即将缓冲区中的数据立刻写入文件,同时清空缓冲区,不需要是被动的等待输出缓冲区写入。
    一般情况下,文件关闭后会自动刷新缓冲区,但有时你需要在关闭前刷新它,这时就可以使用 flush() 方法。
  • commit():涉及到更改数据表中的内容,都要在处理之后使用该方法。

exc_info()

exc_info() 方法会将当前的异常信息以元组的形式返回,该元组中包含 3 个元素,分别为 type、value 和 traceback,它们的含义分别是:
  1. type:异常类型的名称,它是 BaseException 的子类
  2. value:捕获到的异常实例。
  3. traceback:是一个 traceback 对象。

Python操作MySQL基本用法

Python操作MySQL

下边的内容涉及到的Flask知识点较多,可以先看下面这两篇博客。

  1. Flask框架基础
  2. Flask进阶

# 用户登录功能实现

创建表单类

from wtforms import Form, StringField, TextAreaField, PasswordField
from wtforms.validators import DataRequired,Length,ValidationError
from flask_wtf import FlaskForm
# 导入我么自己创建的 操作数据库的类
from mysql_util import MysqlUtil

# Register Form Class
class LoginForm(FlaskForm):
    username = StringField(
        '用户名',
        validators=[
            DataRequired(message='请输入用户名'),
            Length(min=2, max=25,message='长度在4-25个字符之间')
        ]
    )
    password = PasswordField(
        '密码',
        validators = [
            DataRequired(message='密码不能为空'),
            Length(min=6,max=20,message='长度在6-20个字符之间'),
        ]
    )

    def validate_username(self,field):
        sql = "SELECT * FROM users  WHERE username = '%s'" % (field.data) # 根据用户名查找user表中记录
        db = MysqlUtil() # 实例化数据库操作类
        result = db.fetchone(sql) # 获取一条记录
        if not result:
            raise ValidationError("用户名不存在")

上述代码中,在Login Form中定义了useamepassword字段,它们分别对应着登录页面表单中的用户名和密码。
此外,还使用validate多段名函数对usermame字段添加自定义验证规则,判断用户名是否存在。

实现登录功能

当用户填写登录信息后,如果验证全部通过,需要将登录标识username写入Session中,为后面判断用户是否登录做准备。此外,还需要在用户访问/logm路由时,判断用户是否已经登录。如果用
户之前已经登录过,那么则不需要再次登录,而是直接跳转到控制台。

@app.route('/login', methods=['GET', 'POST'])
def login():
    if "logged_in" in session:  # 如果已经登录,则直接跳转到控制台
        return redirect(url_for("dashboard"))

    form = LoginForm(request.form)  # 实例化表单类
    if form.validate_on_submit():   # 如果提交表单,并字段验证通过
        # 从表单中获取字段
        username = request.form['username']
        password_candidate = request.form['password'] # 用户填写的密码
        sql = "SELECT * FROM users  WHERE username = '%s'" % (username) # 根据用户名查找user表中记录
        db = MysqlUtil() # 实例化数据库操作类
        result = db.fetchone(sql) # 获取一条记录
        password = result['password']  # 用户注册时候的密码
        # 对比用户填写的密码和数据库中记录密码是否一致
        if sha256_crypt.verify(password_candidate, password): # 调用verify方法验证,如果为真,验证通过
            # 写入session
            session['logged_in'] = True
            session['username'] = username
            flash('登录成功!', 'success') # 闪存信息
            return redirect(url_for('dashboard')) # 跳转到控制台
        else:  # 如果密码错误
            flash('用户名和密码不匹配!', 'danger')  # 闪存信息

    return render_template('login.html',form=form)
request.form

**解释:**通过requset.form可以直接提取请求体中的表单格式的数据, 是一个类字典的对象,所以可以通过request.form['username']获得表单中字段为username对应的数据。

sha256_crypt.verify()

解释:verify()方法第一个参数是用户1输入的密码,第二个参数是数据库加密后的密码,如果返回True,则表示密码相同。

 session['logged_in'] = True

解释:Session对象是一个字典对象,包含会话变量和关联值的键值对。在进行上述设置后,就可以在其余函数中采用session.get('logged_in'),即字典取值的方法判断用户是否已经登录。

  flash('登录成功!', 'success') # 闪存信息

**解释:**是用来闪现需要显示给用户的内容,上面写入后,可以在需要读取的地方进行读取,如

{% for message in get_flashed_messages() %}
    <div class=flash>{{ message }}</div>
 {% endfor %}
 return render_template('login.html',form=form)

**解释:**通过将表单类参数传入模板,在模板中生成一个表单。


# 用户权限管理功能实现 对于需要用户登录后才能访问的路由,我们可以实现一个装饰器。
def is_logged_in(f):
    @wraps(f)
    def wrap(*args, **kwargs):
        if 'logged_in' in session:     # 判断用户是否登录
            return f(*args, **kwargs)  # 如果登录,继续执行被装饰的函数
        else:                          # 如果没有登录,提示无权访问
            flash('无权访问,请先登录', 'danger')
            return redirect(url_for('login'))
    return wrap
  • 装饰器的作用: 在不改变原有功能代码的基础上,添加额外的功能,如用户验证等。
  • @wraps(view_func)的作用: 不改变使用装饰器原有函数的结构(如name, doc)
  • 需要导入库:from functools import wraps
  • *args:表示任何多个无名参数,它是一个tuple
  • **kwargs:表示关键字参数,它是一个dict

# 博客模块设计

博客列表功能实现

@app.route('/dashboard')
@is_logged_in
def dashboard():
    db = MysqlUtil() # 实例化数据库操作类
    sql = "SELECT * FROM articles WHERE author = '%s' ORDER BY create_date DESC" % (session['username']) # 根据用户名查找用户笔记信息
    result = db.fetchall(sql) # 查找所有笔记
    if result: # 如果笔记存在,赋值给articles变量
        return render_template('dashboard.html', articles=result)
    else:      # 如果笔记不存在,提示暂无笔记
        msg = '暂无笔记信息'
        return render_template('dashboard.html', msg=msg)
session['username']

**解释:**因为在这之前用户已经登录成功,所以可以用上述方法来获取用户名。

添加博客功能实现

@app.route('/add_article', methods=['GET', 'POST'])
@is_logged_in
def add_article():
    form = ArticleForm(request.form) # 实例化ArticleForm表单类
    if request.method == 'POST' and form.validate(): # 如果用户提交表单,并且表单验证通过
        # 获取表单字段内容
        title = form.title.data
        content = form.content.data
        author = session['username']
        create_date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        db = MysqlUtil() # 实例化数据库操作类
        sql = "INSERT INTO articles(title,content,author,create_date) \
               VALUES ('%s', '%s', '%s','%s')" % (title,content,author,create_date) # 插入数据的SQL语句
        db.insert(sql)
        flash('创建成功', 'success') # 闪存信息
        return redirect(url_for('dashboard'))               # 跳转到控制台
    return render_template('add_article.html', form=form)   # 渲染模板
request.method == 'POST' and form.validate():

解释:validate是验证数据的意思

所以from.validate_on_submit()等价于request.method==' post ' and from.validate()


效果:
在这里插入图片描述
.详细代码可以在评论区留言哦

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2021-08-12 16:33:29  更:2021-08-12 16:34:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 18:11:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码