类型:是一个新闻类型的网站
前后端不分离:耦合度高,如果客户端换成app,那么页面效果会出问题.
技术实现:python3.x+Flask+第三方sdk(云通讯+七牛云)+部署(阿里云)
数据存储:redis + mysql
第三方扩展:七牛云和云通信
部署:基于Ubuntu16.04
在使用pycharm的时候有一个小技巧(快速定位到文件地址):
目的:方便今后做扩展,维护,管理更加高效
操作流程:
1/定义了config
文件
2/将config
配置类抽取到config文件中
3/提供了3中环境下的配置信息
4/提供了一个config_dict
的统一访问入口的字典
config.py
import logging
from datetime import timedelta
from redis import StrictRedis
#设置配置信息(基类配置信息)
class Config(object):
#调试信息
DEBUG = True
SECRET_KEY = "fdfdjfkdjfkdf"
#数据库配置信息
SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root:123456@localhost:3306/info36"
SQLALCHEMY_TRACK_MODIFICATIONS = False
#redis配置信息
REDIS_HOST = "127.0.0.1"
REDIS_PORT = 6379
#session配置信息
SESSION_TYPE = "redis" #设置session存储类型
SESSION_REDIS = StrictRedis(host=REDIS_HOST,port=REDIS_PORT) #指定session存储的redis服务器
SESSION_USE_SIGNER = True #设置签名存储
PERMANENT_SESSION_LIFETIME = timedelta(days=2) #设置session有效期,两天时间
#默认日志级别
LEVEL_NAME = logging.DEBUG
#开发环境配置信息
class DevelopConfig(Config):
pass
#生产(线上)环境配置信息
class ProductConfig(Config):
DEBUG = False
LEVEL_NAME = logging.ERROR
#测试环境配置信息
class TestConfig(Config):
pass
#提供一个统一的访问入口
config_dict = {
"develop":DevelopConfig,
"product":ProductConfig,
"test":TestConfig
}
目的:将初始化信息抽取到单独的文件,方便做统一的管理
操作流程:
1/将manager
中的初始化信息抽取到info的init
文件中
2/定义了create_app
方法接收了一个config_name
参数
3/根据config_name
加载不同的环境下的配置类信息
4/再返回一个完整的app给manager
文件
info包下的__init__.py
import logging
from logging.handlers import RotatingFileHandler
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from redis import StrictRedis
from flask_session import Session
from flask_wtf.csrf import CSRFProtect
from config import config_dict
#定义redis_store变量
redis_store = None
#定义工厂方法
def create_app(config_name):
app = Flask(__name__)
#根据传入的配置类名称,取出对应的配置类
config = config_dict.get(config_name)
#调用日志方法,记录程序运行信息
log_file(config.LEVEL_NAME)
#加载配置类
app.config.from_object(config)
#创建SQLAlchemy对象,关联app
db = SQLAlchemy(app)
#创建redis对象
global redis_store #global将局部变量声明为一个全局的
redis_store = StrictRedis(host=config.REDIS_HOST,port=config.REDIS_PORT,decode_responses=True)
#创建Session对象,读取APP中session配置信息
Session(app)
#使用CSRFProtect保护app
CSRFProtect(app)
#将首页蓝图index_blue,注册到app中
from info.modules.index import index_blue
app.register_blueprint(index_blue)
return app
def log_file(LEVEL_NAME):
# 设置日志的记录等级,常见的有四种,大小关系如下: DEBUG < INFO < WARNING < ERROR
logging.basicConfig(level=LEVEL_NAME) # 调试debug级,一旦设置级别那么大于等于该级别的信息全部都会输出
# 创建日志记录器,指明日志保存的路径、每个日志文件的最大大小、保存的日志文件个数上限
file_log_handler = RotatingFileHandler("logs/log", maxBytes=1024 * 1024 * 100, backupCount=10)
# 创建日志记录的格式 日志等级 输入日志信息的文件名 行数 日志信息
formatter = logging.Formatter('%(levelname)s %(filename)s:%(lineno)d %(message)s')
# 为刚创建的日志记录器设置日志记录格式
file_log_handler.setFormatter(formatter)
# 为全局的日志工具对象(flask app使用的)添加日志记录器
logging.getLogger().addHandler(file_log_handler)
目的:视图函数是用来处理对应业务的,可能有很多,应该使用蓝图进行统一的管理
操作流程:
1/创建了modules
模块,用来管理所有的蓝图
2/再modules
底下创建了index
包
3/在index
中创建了index_blue
蓝图,创建了views
文件,并使用index_blue
装饰视图函数
4/在create_app
方法内部注册index_blue
到app中
modules下的index下的__inint__.py
from flask import Blueprint
#1.创建蓝图对象
index_blue = Blueprint("index",__name__)
#2.导入views文件装饰视图函数
# from info.modules.index import views
from . import views
modules下的index下的views.py
from info import redis_store
from . import index_blue
import logging
from flask import current_app
@index_blue.route('/',methods=["GET","POST"])
def hello_world():
#测试redis存取数据
# redis_store.set("name","laowang")
# print(redis_store.get("name"))
#测试session存取
# session["name"] = "zhangsan"
# print(session.get("name"))
#没有继承日志之前,使用print输出,不方便做控制
# print("helloworld")
#使用日志记录方法loggin进行输出可控
logging.debug("输入调试信息")
logging.info("输入详细信息")
logging.warning("输入警告信息")
logging.error("输入错误信息")
#也可以使用current_app来输出日志信息,输出的时候有分割线,写在文件中完全一样
# current_app.logger.debug("输入调试信息2")
# current_app.logger.info("输入详细信息2")
# current_app.logger.warning("输入警告信息2")
# current_app.logger.error("输入错误信息2")
return "helloworld"
在上面的代码中有可能logging和current_app两个方法导出日志信息的时候,大家不知道其中的一个区别,那么下面用图片给大家演示一下:
上面的图片是在pycharm中的控制台显示效果,当然我们也可以将其输出到日志文件中,他们的区别就是在控制台显示的时候,current_app输出更加的美观,便于查看;但是在日志中,两种方法的效果是完全一样的,没有任何不同
解决办法:在控制台中,查看到底是哪些文件之间产生了循环导包,依次点开所有的文件,只需要想办法断掉其中一环即可
ImportError: cannot import name 'redis_store'
循环导包错误
问题:
1/redis_store
创建再了create_app
方法内部,外界不能导入使用
2/在create_app
方法外部创建一个空的redis_store
使用global装饰方法内部的redis_store
即可
目的:
1/记录用户的行为
2/记录分析软件的问题
3/便于给产品经理提供设计依据
日志最大的限制,够了之后会再生成一个log文件,最多10个日志,编号是10,有个没有编号的,其实是11个.如果文件不够用了,会将最开始的文件给删除,最后建一个文件,然后将所有日志文件编号从新排一下
操作流程:
1/定义好log_file
方法,拷贝日志记录方法进来
2/在create_app
方法中调用即可
import logging
from logging.handlers import RotatingFileHandler
def log_file(LEVEL_NAME):
# 设置日志的记录等级,常见的有四种,大小关系如下: DEBUG < INFO < WARNING < ERROR
logging.basicConfig(level=LEVEL_NAME) # 调试debug级,一旦设置级别那么大于等于该级别的信息全部都会输出
# 创建日志记录器,指明日志保存的路径、每个日志文件的最大大小、保存的日志文件个数上限
file_log_handler = RotatingFileHandler("logs/log", maxBytes=1024 * 1024 * 100, backupCount=10)
# 创建日志记录的格式 日志等级 输入日志信息的文件名 行数 日志信息
formatter = logging.Formatter('%(levelname)s %(filename)s:%(lineno)d %(message)s')
# 为刚创建的日志记录器设置日志记录格式
file_log_handler.setFormatter(formatter)
# 为全局的日志工具对象(flask app使用的)添加日志记录器
logging.getLogger().addHandler(file_log_handler)
目的:为了便于去管理不同环境下的日志级别
操作流程:
1/在config
配置文件中,给DevelopConfig和ProductConfig
设置不同的级别
2/在调用create_app
方法的时候,传递对应环境的key值
3/取出对应的环境下的日志级别,将日志级别传递到log_file
方法中
当前的一个目录结构:
from config import config_dict
#定义工厂方法
def create_app(config_name):
app = Flask(__name__)
#根据传入的配置类名称,取出对应的配置类
config = config_dict.get(config_name)
#调用日志方法,记录程序运行信息
log_file(config.LEVEL_NAME)
config配置文件
import logging
#设置配置信息(基类配置信息)
class Config(object):
....
#默认日志级别
LEVEL_NAME = logging.DEBUG
#开发环境配置信息
class DevelopConfig(Config):
pass
#生产(线上)环境配置信息
class ProductConfig(Config):
DEBUG = False
LEVEL_NAME = logging.ERROR
import logging
from logging.handlers import RotatingFileHandler
def log_file(LEVEL_NAME):
# 设置日志的记录等级,常见的有四种,大小关系如下: DEBUG < INFO < WARNING < ERROR
logging.basicConfig(level=LEVEL_NAME) # 调试debug级,一旦设置级别那么大于等于该级别的信息全部都会输出
下面将上面的过程用图片进行一个演示
目的:可以让logs
空文件夹能够被提交到git仓库
创建方法:直接在logs文件夹下建立一个空的文件名字为.gitkeep
目的:主要是了解xx网站中的主要的7张表之间的关系
注意点:看keynote的图
目的:将模型类迁移成数据库的具体表
操作流程:
1/导入models,constants文件到info中
2/将create_app中的SQLAlchemy(app),改成两句话
1/db= Sqlalchemy(),定义在create_app外部
2/db.init_app(app),定义在create_app内部
3/在manager.py文件中进行迁移
1/导入Manager,Migrate,MigrateCommand
2/创建manager对象管理app
3/使用Migrate,挂链app,db
4/给manager添加一条操作命令
5/执行迁移(init,Migrate,upgrade)
目的:为了给用户提供访问页面
操作流程:将status文件夹添加到info里面,然后使用Git管理起来
目的:在用户访问首页的时候可以给用户
操作步骤:
1/先在info中创建一个template文件夹
2/将status/news中的 index.html拖入到templates/news文件夹中
3/再访问根路径的时候,使用render_template将index.html渲染出来
目的:显示网站的标识,显示在title中
注意点:
1/当浏览器访问每个网站的时候都会自动去请求一个/favicon.ico的接口
2/我们只需要在程序中,写上/favicon.ico的接口,然后返回一张图片即可
3/在flask中需要使用一个方法current_app.send_static_file("文件名")
1/send_static_file("文件1"),该方法会自动去static静态文件夹中寻找文件1
目的:为了保证注册,登录的用户是个真实的用户在操作,为了去获取短信验证码
注意点:
1/在服务器内部保存图片验证码的时候,前端需要带一个随机字符串(uuid)过来
2/uuid作为key,图片验证码的值作为value存储
目的:便于程序调用,生成图片验证码
操作流程:
1/在info中创建utils包,将captch导入即可
目的:为了方便前端调用,获取图片验证码
目的: 不能在服务端存储多份图片,容易导致后端的服务器内存不足
操作流程
1/获取参数,cur_id,pre_id
2/调用generator_captch()生成图片验证码
3/存储图片验证码到redis
4/判断是否有上一次图片验证码,如果有则删除
5/返回一张图片,并指定图片格式
优质文章推荐: