Python Flask搭建个人博客详细回顾—(2.1 项目结构,初始化配置等)

个人博客Demo: link.
GitHub项目完整链接:link


回顾上一节主要讲了搭建个人博客之前开发环境的配置,主要囊括三个方面

  • 安装pipenv,设置虚拟环境,安装相关依赖包
  • pycharm开发工具的环境配置
  • MySQL的安装

2.1.1 博客结构

  • 功能结构大致如图:
    在这里插入图片描述
  • 用思维导图表示了文件结构,如图:
    在这里插入图片描述

2.1.2 编写配置文件:settings.py

基础配置类:

  • 用os.getenv从环境变量中获取程序密钥SECRET_KEY(用于cookies,session等加密),同时在第二参数设置默认值
  • 设置数据库的相关配置参数
  • 设置CKEditor的相关配置,如CKEDITOR_ENABLE_CSRF = True开启CSRF保护
  • 博客自定义参数,如:博客文章每页显示数量设置,文件上传格式限制等

开发配置类:

  • 继承基本配置类,配置连接MySQL数据库的URI路径
  • MySQL URI配置方法:‘mysql+pymysql:// mysql用户名 : mysql密码 @ 端口值,默认:localhost:3306 / mysql里创建的数据库名’

生产配置类:

  • 继承基本配置类,从环境变量DATABASE_URL中获取数据库URI

配置映射字典方便加载配置
代码如下:

import os

basedir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))   # 根目录


class BaseConfig(object):
    SECRET_KEY = os.getenv('SECRET_KEY', 'this is secret')  # 获取程序密钥

    SQLALCHEMY_TRACK_MODIFICATIONS = False  # 关闭数据库警告信息
    SQLALCHEMY_RECORD_QUERIES = True  # 启用查询记录

    CKEDITOR_ENABLE_CSRF = True  # 开启CSRF保护
    CKEDITOR_FILE_UPLOADER = 'admin.upload_image'  # cke图片上传视图函数路径(需编写)

    BLOG_POST_PER_PAGE = 7  # 每页文章数
    BLOG_MANAGE_POST_PER_PAGE = 15  # 后台管理界面每页文章数
    BLOG_COMMENT_PER_PAGE = 10  # 每页评论数
    BLOG_MANAGE_COMMENT_PER_PAGE = 15  # 后台管理每页评论数

    BLOG_UPLOAD_PATH = os.path.join(basedir, 'uploads')  # 上传文件夹路径
    BLOG_ALLOWED_IMAGE_EXTENSIONS = ['jpg', 'png', 'gif', 'jpeg']  # 上传图片支持格式


class DevelopmentConfig(BaseConfig):
    SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:hejian1363531=@localhost:3306/blogdb'


class ProductionConfig(BaseConfig):
    SQLALCHRMY_DATABASE_URI = os.getenv('DATABASE_URL')


# 配置映射字典,方便调用
config = {
    'development': DevelopmentConfig,
    'production': ProductionConfig
}

2.1.3 拓展实例化: extensions.py

在extensions.py文件中进行拓展类的实例化操作,而拓展的初始化操作在__init__.py构造文件中声明。目的是创建可以全局使用的拓展对象如:db = SQLAlchemy()。
代码如下:

from flask_sqlalchemy import SQLAlchemy
from flask_ckeditor import CKEditor
from flask_moment import Moment
from flask_bootstrap import Bootstrap
from flask_login import LoginManager
from flask_wtf.csrf import CSRFProtect


bootstrap = Bootstrap()
db = SQLAlchemy()
moment = Moment()
ckeditor = CKEditor()
login = LoginManager()
csrf = CSRFProtect()

2.1.4 创建数据库模型: models.py

在博客的数据库模型中我们需要创建四张表分别为:

  • 管理员(Admin) 囊括主键,用户名,登录密码以及博客设置方面的博客标题,关于信息等字段。需要注意的是Admin模型中并不直接存储用户密码而是存储相应密码hash值,直接存储密码非常危险,通过定义set_password()和validate_password()两个方法对原始密码加密成hash值,在验证时也通过比对hash值进行用户验证
  • 分类(Category) 包括主键及分类名字段,分类与文章之间是一对多关系
  • 文章(Post) 包括文章标题,内容,时间戳等字段,文章和评论是一对多关系
  • 评论(Comment) 包括评论作者,评论内容时间戳等字段,回复也是评论的一种,在评论模型内建立邻接列表关系(即同一模型内的一对多关系)
    代码如下:
from flask_moment import datetime
from Blog.extensions import db
from flask_login import UserMixin


# 管理员类(存储用户名,密码hash值,博客相关设置)
class Admin(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(20))  # 用户名(用于登录)
    password_hash = db.Column(db.String(128))	# 存储密码hash值
    # 博客设置
    blog_title = db.Column(db.String(60))   # 博客标题
    name = db.Column(db.String(30))  # 用户昵称(评论中显示)
    about = db.Column(db.Text)
	
	def set_password(self,password):	# 将输入的密码转换成hash值进行加密
        self.password_hash = generate_password_hash(password)

    def validate_password(self, password):	 # 对输入的密码转换成hash值跟存储的hash值进行比对
        return check_password_hash(self.password_hash, password)


# 分类
class Category(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(30), unique=True)    # 分类名不允许重复,unique=True
    # back_populates为SQLAlchemy的关系函数参数,用于定义反向引用,建立双向关系,在关系的另一侧也必须显式定义关系属性
    posts = db.relationship('Post', back_populates='category')	# 集合关系属性


# 文章
class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(30))
    timestamp = db.Column(db.DateTime, default=datetime.utcnow)  # 时间戳
    body = db.Column(db.Text)
    can_comments = db.Column(db.Boolean, default=True)	# 文章能否评论开关

    category_id = db.Column(db.Integer, db.ForeignKey('category.id'))    # 将category_id设置为外键
    category = db.relationship('Category', back_populates='posts')	# 标量关系属性
    
	 # 设置集合关系属性,cascade设置级联操作,文章删除,文章下的评论也删除
    comments = db.relationship('Comment', back_populates='post', cascade='all, delete-orphan') 


# 评论
class Comment(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    author = db.Column(db.String(20))
    timestamp = db.Column(db.DateTime, default=datetime.utcnow)
    body = db.Column(db.Text)
    from_admin = db.Column(db.Boolean, default=False)	# 判断评论是否来自管理员
    reviewed = db.Column(db.Boolean, default=False)	 # 判断评论是否已读

    post_id = db.Column(db.Integer, db.ForeignKey('post.id'))	# 将文章主键id设置为外键
    post = db.relationship('Post', back_populates='comments')	# 标量关系属性
    # 建立邻接列表关系(在同一个模型内的一对多关系)
    replied_id = db.Column(db.Integer, db.ForeignKey('comment.id'))	 # 在replied设置外键(comment.id)
    # replied表示被回复评论的标量关系属性, remote_side=[id]将id字段定义为关系远程侧
    replied = db.relationship('Comment', back_populates='replies', remote_side=[id])
    replies = db.relationship('Comment', back_populates='replied', cascade='all')	# 集合关系

2.1.5 生成虚拟数据 fakes.py

生成虚拟数据的目的是为了方便测试博客网站的功能
fakes.py生成管理员信息,分类,文章以及评论(包括游客评论,未读评论,管理员评论以及回复)
代码虽然不短,但实际内容比较简单,参考代码里的注释和models.py很容易理解,不再赘述

代码如下:

import random
from Blog.models import Admin, Category, Post, Comment
from Blog.extensions import db
from faker import Faker
from sqlalchemy.exc import IntegrityError

fake = Faker()  # 实例化Faker


def fake_admin():
    # 设置管理员用户名密码等
    admin = Admin(
        username='nidemingzi',
        blog_title="nidemingzi'blog",
        name='一头特立独行的猪',
        about="Welcome to my personal website,um,i ,likes uses python to coding"
    )
    admin.set_password('helloflask')    # 调用Admin类下的ser_password()方法设置密码
    db.session.add(admin)   # 添加到数据库临时会话
    db.session.commit()  # 提交数据库会话


def fake_category(count=5):
    # 定义默认分类
    category = Category(name='Default')
    db.session.add(category)

    # 迭代生成5个虚拟分类
    for i in range(count):
        category = Category(name=fake.word())
        db.session.add(category)
        # 若随机生成分类名重复则回滚,取消添加到category的临时会话
        try:
            db.session.commit()
        except IntegrityError:
            db.session.rollback()


def fake_post(count=25):
    for i in range(count):
        post = Post(
            title=fake.sentence(),
            body=fake.text(2000),
            category=Category.query.get(random.randint(1, Category.query.count())),  # 文章随机分配到某个分类
            timestamp=fake.date_time_this_year()
        )
        db.session.add(post)
    db.session.commit()


def fake_comment(count=150):
    for i in range(count):
        comment = Comment(
            author=fake.name(),
            body=fake.sentence(),
            timestamp=fake.date_time_this_year(),
            post=Post.query.get(random.randint(1, Post.query.count())),  # 评论随机分配到某篇文章中
            reviewed=True
        )
        db.session.add(comment)
    db.session.commit()

    # 生成管理员评论
    salt = int(0.1*count)
    for i in range(salt):
        comment = Comment(
            author='一头特立独行的猪',
            from_admin=True,
            reviewed=True,
            body=fake.sentence(),
            timestamp=fake.date_time_this_year(),
            post=Post.query.get(random.randint(1, Post.query.count()))
        )
        db.session.add(comment)
    db.session.commit()

    # 生成未读评论
    for i in range(salt):
        comment = Comment(
            author=fake.name(),
            body=fake.sentence(),
            timestamp=fake.date_time_this_year(),
            replied=Comment.query.get(random.randint(1, Comment.query.count())),
            post=Post.query.get(random.randint(1, Post.query.count())),
            reviewed=False
        )
        db.session.add(comment)
    db.session.commit()
    # 生成回复
    for i in range(salt):
        comment = Comment(
            author=fake.name(),
            body=fake.sentence(),
            timestamp=fake.date_time_this_year(),
            reviewed=True,
            replied=Comment.query.get(random.randint(1, Comment.query.count())),
            post=Post.query.get(random.randint(1, Post.query.count()))
        )
        db.session.add(comment)
    db.session.commit()

后面会介绍__init__.py构造文件如何程序实例以及函数的注册,forms.py编写表单等内容

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值