一、初始化flask实例
在项目路径下,建立一个用于初始化app的实例对象的app.py文件和一个用于项目启动的文件(一般与项目同名)的py文件,这里使用manage.py作为示例。
# vi app.py
from flask import Flask
from configs import Config
def create_app(config):
app = Flask(__name__,static_folder=Config.STATIC_FOLDER, template_folder=Config.TEMPLATES_FOLDER)
# 加载配置文件
app.config.from_object(config)
return app
# vi manage.py
from flask_script import Manager
from app import create_app
from configs import DevConfig
from models import db
from flask_migrate import Migrate, MigrateCommand
# 初始化flask实例并加载配置文件
app = create_app(DevConfig)
# 为app对象添加扩展命令
manager = Manager(app)
# 完成连接数据库的初始化
db.init_app(app)
Migrate(app, db)
# 添加扩展的数据库迁移命令
manager.add_command("db", MigrateCommand)
if __name__ == '__main__':
manager.run()
# 配置文件如下:
class Config(object):
Debug = False
# 模板目录
TEMPLATES_FOLDER = os.path.join(BASE_DIR, "templates")
# 静态文件目录
STATIC_FOLDER = os.path.join(BASE_DIR, "static")
SQLALCHEMY_DATABASE_URI = 'mysql://root:123456@host:3310/xjzx10'
SQLALCHEMY_TRACK_MODIFICATIONS = True
class DevConfig(Config):
Debug = True
class UatConfig(Config):
Debug = True
class ProConfig(Config):
Debug = False
启动命令:python manage runserver -h 0.0.0.0 -p 5000
二、路由蓝图
在项目目录下,新建一个用于注册user的视图路由的user_views.py文件,内容如下:
from flask import Blueprint, render_template
user_blueprint = Blueprint('user', __name__, url_prefix="user")
# 注册路由
@news_blueprint.route('/')
def index():
return render_template('index.html')
在项目目录下,新建一个用于注册admin的视图路由的admin_views.py文件,内容如下:
from flask import Blueprint
admin_blueprint = Blueprint('admin', __name__, url_prefix="/admin")
在app.py文件中注册蓝图:
from flask import Flask
from user_views import user_blueprint
from admin_views import admin_blueprint
def create_app(config):
app = Flask(__name__)
app.config.from_object(config)
app.register_blueprint(user_blueprint)
app.register_blueprint(admin_blueprint)
return app
三、建立模型
在项目目录下,创建一个model.py的文件,内容如下:
import pymysql
from datetime import datetime
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash, check_password_hash
pymysql.install_as_MySQLdb()
db = SQLAlchemy()
class BaseModel(object):
create_time = db.Column(db.DateTime, default=datetime.now())
update_time = db.Column(db.DateTime, default=datetime.now())
isDelete = db.Column(db.Boolean, default=False)
tb_news_collect = db.Table(
'tb_news_collect',
db.Column('user_id', db.Integer, db.ForeignKey('user_info.id'), primary_key=True),
db.Column('news_id', db.Integer, db.ForeignKey('news_info.id'), primary_key=True)
)
tb_user_follow = db.Table(
'tb_user_follow',
db.Column('origin_user_id', db.Integer, db.ForeignKey('user_info.id'), primary_key=True),
db.Column('follow_user_id', db.Integer, db.ForeignKey('user_info.id'), primary_key=True)
)
class NewsCategory(db.Model, BaseModel):
__tablename__ = 'news_category'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(10))
#关系属性:不会在表中生成字段
#lazy='dynamic'惰性加载category.news
#category=NewsCategory.query.get(1)
#当使用lazy='dynamic'时不会查询分类的新闻信息
#这样设置的好处:可能本次只是使用分类对象,不想使用新闻对象,则可以减少数据库的查询量
news = db.relationship('NewsInfo', backref='category', lazy='dynamic')
class NewsInfo(db.Model, BaseModel):
__tablename__ = 'news_info'
id = db.Column(db.Integer, primary_key=True)
category_id = db.Column(db.Integer, db.ForeignKey('news_category.id'))
pic = db.Column(db.String(50))
title = db.Column(db.String(30))
summary = db.Column(db.String(200))
content = db.Column(db.Text)
user_id = db.Column(db.Integer, db.ForeignKey('user_info.id'))
click_count = db.Column(db.Integer, default=0)
comment_count = db.Column(db.Integer, default=0)
status = db.Column(db.SmallInteger, default=1)
reason=db.Column(db.String(100),default='')
comments = db.relationship('NewsComment', backref='news', lazy='dynamic', order_by='NewsComment.id.desc()')
# @property
# def pic_url(self):
# return current_app.config.get('QINIU_URL') + self.pic
#
# def to_index_dict(self):
# return {
# 'id': self.id,
# 'pic_url': self.pic_url,
# 'title': self.title,
# 'summary': self.summary,
# 'author': self.user.nick_name,
# 'author_avatar': self.user.avatar_url,
# 'author_id': self.user_id,
# 'udpate_time': self.update_time.strftime('%Y-%m-%d')
# }
class UserInfo(db.Model,BaseModel):
__tablename__ = 'user_info'
id = db.Column(db.Integer, primary_key=True)
avatar = db.Column(db.String(50), default='user_pic.png')
nick_name = db.Column(db.String(20))
signature = db.Column(db.String(200))
public_count = db.Column(db.Integer, default=0)
follow_count = db.Column(db.Integer, default=0)
mobile = db.Column(db.String(11))
password_hash = db.Column(db.String(200))
gender = db.Column(db.Boolean, default=False)
isAdmin = db.Column(db.Boolean, default=False)
#用户对新闻为1:多,所以将新闻关联属性定义在User类中
news = db.relationship('NewsInfo', backref='user', lazy='dynamic')
#用户对评论为1:多,所以将评论关联属性定义在User类中
comments = db.relationship('NewsComment', backref='user', lazy='dynamic')
#用户对收藏新闻为多:多,此时关系属性可以定义在任意类中,当前写在了User类中
news_collect = db.relationship(
'NewsInfo',
#多对多时,指定关系表,因为外键存储在这个关系表中
secondary=tb_news_collect,
lazy='dynamic'
#此处没有定义backref,作用是根据新闻找用户,因为不需要使用这个功能,所以可以不定义
)
#用户关注用户为自关联多对多,关系属性只能定义在User类中
#使用user.follow_user可以获得当前user用户关注的用户列表
#select * from users inner join tb_user_follow on user.id=origin_user_id
follow_user = db.relationship(
'UserInfo',
#多对多,所以指定关系表
secondary=tb_user_follow,
lazy='dynamic',
#user.follow_by_user可以获得当前user用户的粉丝用户列表
backref=db.backref('follow_by_user', lazy='dynamic'),
#在使用user.follow_user时,user.id与关系表中哪个字段判等
primaryjoin=id == tb_user_follow.c.origin_user_id,
#在使用user.follow_by_user时,user.id与关系表中的哪个字段判等
secondaryjoin=id == tb_user_follow.c.follow_user_id
)
@property
def password(self):
pass
@password.setter
def password(self, pwd):
self.password_hash = generate_password_hash(pwd)
def check_pwd(self, pwd):
return check_password_hash(self.password_hash, pwd)
# @property
# def avatar_url(self):
# return current_app.config.get('QINIU_URL') + self.avatar
class NewsComment(db.Model, BaseModel):
__tablename__ = 'news_comment'
id = db.Column(db.Integer, primary_key=True)
news_id = db.Column(db.Integer, db.ForeignKey('news_info.id'))
user_id = db.Column(db.Integer, db.ForeignKey('user_info.id'))
like_count = db.Column(db.Integer, default=0)
comment_id = db.Column(db.Integer, db.ForeignKey('news_comment.id'))
msg = db.Column(db.String(200))
comments = db.relationship('NewsComment', lazy='dynamic')
迁移命令:
python '文件名' db init 创建迁移仓库
python '文件名' db migrate -m '版本号' 创建自动迁移脚本
python '文件名' db upgrade 更新数据库
python '文件名' db history 查看历史版本
python '文件名' db downgrade '版本号'(系统定义的版本号) 回退数据库
四、日记
在项目目录下,创建一个logs的目录,然后在其子目录下创建想要的配置的日记文件,如connect或error等等;在项目目录下,创建一个log.py文件,内容如下:
import logging
from logging.handlers import RotatingFileHandler
class Logger(object):
def __innit__(self):
# logging初始化工作
logging.basicConfig()
# 创建日志记录器,指明日志保存的路径、每个日志文件的最大大小、保存的日志文件个数上限
connect_file_log_handler = RotatingFileHandler(config.BASE_DIR + "/logs/connect.log", maxBytes=1024 * 1024 * 100,backupCount=10)
# 创建日志记录的格式 日志等级 输入日志信息的文件名 行数 日志信息
formatter = logging.Formatter('%(levelname)s %(filename)s:%(lineno)d %(message)s')
# 为刚创建的日志记录器设置日志记录格式
connect_file_log_handler.setFormatter(formatter)
# connect的初始化工作
self.logger_connect = logging.getLogger("connect")
# 设置connect的日记等级
self.logger_connect.setLevel(logging.INFO)
self.logger_connect.addHandler(connect_file_log_handler)
# 创建日志记录器,指明日志保存的路径、每个日志文件的最大大小、保存的日志文件个数上限
error_file_log_handler = RotatingFileHandler(config.BASE_DIR + "/logs/error.log", maxBytes=1024 * 1024 * 100,backupCount=10)
# 为刚创建的日志记录器设置日志记录格式
error_file_log_handler.setFormatter(formatter)
# error的初始化工作
self.logger_error = logging.getLogger("error")
# 设置connect的日记等级
self.logger_error.setLevel(logging.error)
self.logger_error.addHandler(error_file_log_handler)
def connect(self,msg):
self.logger_connect.info(msg)
def error(self,msg):
self.logger_error.info(msg)
logger = Logger()
可以将日记对象初始化到app的实例中,然后使用flask中的上下文管理对象current_app调用更为方便:
# vi app.py
from flask import Flask
from user_views import user_blueprint
from admin_views import admin_blueprint
from log import logger
def create_app(config):
app = Flask(__name__)
app.config.from_object(config)
app.register_blueprint(user_blueprint)
app.register_blueprint(admin_blueprint)
app.connect = logger.connect
app.error = logger.error
return app