经典案例之某新闻网站的实现

1.项目介绍

类型:是一个新闻类型的网站

前后端不分离:耦合度高,如果客户端换成app,那么页面效果会出问题.

技术实现:python3.x+Flask+第三方sdk(云通讯+七牛云)+部署(阿里云)

数据存储:redis + mysql

第三方扩展:七牛云和云通信

部署:基于Ubuntu16.04

在使用pycharm的时候有一个小技巧(快速定位到文件地址):

2.配置文件抽取

目的:方便今后做扩展,维护,管理更加高效

操作流程:

1/定义了config文件

2/将config配置类抽取到config文件中

3/提供了3中环境下的配置信息

4/提供了一个config_dict的统一访问入口的字典

config.py

 1import logging
 2from datetime import timedelta
 3from redis import StrictRedis
 4
 5#设置配置信息(基类配置信息)
 6class Config(object):
 7    #调试信息
 8    DEBUG = True
 9    SECRET_KEY = "fdfdjfkdjfkdf"
10
11    #数据库配置信息
12    SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root:123456@localhost:3306/info36"
13    SQLALCHEMY_TRACK_MODIFICATIONS = False
14
15    #redis配置信息
16    REDIS_HOST = "127.0.0.1"
17    REDIS_PORT = 6379
18
19    #session配置信息
20    SESSION_TYPE = "redis" #设置session存储类型
21    SESSION_REDIS = StrictRedis(host=REDIS_HOST,port=REDIS_PORT) #指定session存储的redis服务器
22    SESSION_USE_SIGNER = True #设置签名存储
23    PERMANENT_SESSION_LIFETIME = timedelta(days=2) #设置session有效期,两天时间
24
25    #默认日志级别
26    LEVEL_NAME = logging.DEBUG
27
28#开发环境配置信息
29class DevelopConfig(Config):
30    pass
31
32
33#生产(线上)环境配置信息
34class ProductConfig(Config):
35    DEBUG = False
36    LEVEL_NAME = logging.ERROR
37
38
39#测试环境配置信息
40class TestConfig(Config):
41    pass
42
43
44#提供一个统一的访问入口
45config_dict = {
46    "develop":DevelopConfig,
47    "product":ProductConfig,
48    "test":TestConfig
49}

3.初始化信息抽取

目的:将初始化信息抽取到单独的文件,方便做统一的管理

操作流程:

1/将manager中的初始化信息抽取到info的init文件中

2/定义了create_app方法接收了一个config_name参数

3/根据config_name加载不同的环境下的配置类信息

4/再返回一个完整的app给manager文件

info包下的__init__.py

 1import logging
 2from logging.handlers import RotatingFileHandler
 3
 4from flask import Flask
 5from flask_sqlalchemy import SQLAlchemy
 6from redis import StrictRedis
 7from flask_session import Session
 8from flask_wtf.csrf import CSRFProtect
 9from config import config_dict
10
11#定义redis_store变量
12redis_store = None
13
14#定义工厂方法
15def create_app(config_name):
16    app = Flask(__name__)
17
18    #根据传入的配置类名称,取出对应的配置类
19    config = config_dict.get(config_name)
20
21    #调用日志方法,记录程序运行信息
22    log_file(config.LEVEL_NAME)
23
24    #加载配置类
25    app.config.from_object(config)
26
27    #创建SQLAlchemy对象,关联app
28    db = SQLAlchemy(app)
29
30    #创建redis对象
31    global redis_store #global将局部变量声明为一个全局的
32    redis_store = StrictRedis(host=config.REDIS_HOST,port=config.REDIS_PORT,decode_responses=True)
33
34    #创建Session对象,读取APP中session配置信息
35    Session(app)
36
37    #使用CSRFProtect保护app
38    CSRFProtect(app)
39
40    #将首页蓝图index_blue,注册到app中
41    from info.modules.index import index_blue
42    app.register_blueprint(index_blue)
43
44    return app
45
46def log_file(LEVEL_NAME):
47    # 设置日志的记录等级,常见的有四种,大小关系如下: DEBUG < INFO < WARNING < ERROR
48    logging.basicConfig(level=LEVEL_NAME)  # 调试debug级,一旦设置级别那么大于等于该级别的信息全部都会输出
49    # 创建日志记录器,指明日志保存的路径、每个日志文件的最大大小、保存的日志文件个数上限
50    file_log_handler = RotatingFileHandler("logs/log", maxBytes=1024 * 1024 * 100, backupCount=10)
51    # 创建日志记录的格式 日志等级 输入日志信息的文件名 行数 日志信息
52    formatter = logging.Formatter('%(levelname)s %(filename)s:%(lineno)d %(message)s')
53    # 为刚创建的日志记录器设置日志记录格式
54    file_log_handler.setFormatter(formatter)
55    # 为全局的日志工具对象(flask app使用的)添加日志记录器
56    logging.getLogger().addHandler(file_log_handler)

4.视图函数抽取

目的:视图函数是用来处理对应业务的,可能有很多,应该使用蓝图进行统一的管理

操作流程:

1/创建了modules模块,用来管理所有的蓝图

2/再modules底下创建了index

3/在index中创建了index_blue蓝图,创建了views文件,并使用index_blue装饰视图函数

4/在create_app方法内部注册index_blue到app中

modules下的index下的__inint__.py

1from flask import Blueprint
2
3#1.创建蓝图对象
4index_blue = Blueprint("index",__name__)
5
6#2.导入views文件装饰视图函数
7# from info.modules.index import views
8from . import views

modules下的index下的views.py

 1from info import redis_store
 2from . import index_blue
 3import logging
 4from flask import current_app
 5
 6@index_blue.route('/',methods=["GET","POST"])
 7def hello_world():
 8
 9    #测试redis存取数据
10    # redis_store.set("name","laowang")
11    # print(redis_store.get("name"))
12
13    #测试session存取
14    # session["name"] = "zhangsan"
15    # print(session.get("name"))
16
17    #没有继承日志之前,使用print输出,不方便做控制
18    # print("helloworld")
19
20    #使用日志记录方法loggin进行输出可控
21    logging.debug("输入调试信息")
22    logging.info("输入详细信息")
23    logging.warning("输入警告信息")
24    logging.error("输入错误信息")
25
26    #也可以使用current_app来输出日志信息,输出的时候有分割线,写在文件中完全一样
27    # current_app.logger.debug("输入调试信息2")
28    # current_app.logger.info("输入详细信息2")
29    # current_app.logger.warning("输入警告信息2")
30    # current_app.logger.error("输入错误信息2")
31
32
33    return "helloworld"


在上面的代码中有可能logging和current_app两个方法导出日志信息的时候,大家不知道其中的一个区别,那么下面用图片给大家演示一下:

上面的图片是在pycharm中的控制台显示效果,当然我们也可以将其输出到日志文件中,他们的区别就是在控制台显示的时候,current_app输出更加的美观,便于查看;但是在日志中,两种方法的效果是完全一样的,没有任何不同

5.循环导包

解决办法:在控制台中,查看到底是哪些文件之间产生了循环导包,依次点开所有的文件,只需要想办法断掉其中一环即可

ImportError: cannot import name 'redis_store'循环导包错误

6.redis存储设置

问题:

1/redis_store创建再了create_app方法内部,外界不能导入使用

2/在create_app方法外部创建一个空的redis_store使用global装饰方法内部的redis_store即可

7.日志信息集成

目的:

1/记录用户的行为

2/记录分析软件的问题

3/便于给产品经理提供设计依据

日志最大的限制,够了之后会再生成一个log文件,最多10个日志,编号是10,有个没有编号的,其实是11个.如果文件不够用了,会将最开始的文件给删除,最后建一个文件,然后将所有日志文件编号从新排一下

操作流程:

1/定义好log_file方法,拷贝日志记录方法进来

2/在create_app方法中调用即可

 1import logging
 2from logging.handlers import RotatingFileHandler
 3def log_file(LEVEL_NAME):
 4    # 设置日志的记录等级,常见的有四种,大小关系如下: DEBUG < INFO < WARNING < ERROR
 5    logging.basicConfig(level=LEVEL_NAME)  # 调试debug级,一旦设置级别那么大于等于该级别的信息全部都会输出
 6    # 创建日志记录器,指明日志保存的路径、每个日志文件的最大大小、保存的日志文件个数上限
 7    file_log_handler = RotatingFileHandler("logs/log", maxBytes=1024 * 1024 * 100, backupCount=10)
 8    # 创建日志记录的格式 日志等级 输入日志信息的文件名 行数 日志信息
 9    formatter = logging.Formatter('%(levelname)s %(filename)s:%(lineno)d %(message)s')
10    # 为刚创建的日志记录器设置日志记录格式
11    file_log_handler.setFormatter(formatter)
12    # 为全局的日志工具对象(flask app使用的)添加日志记录器
13    logging.getLogger().addHandler(file_log_handler)

8.日志配置抽取

目的:为了便于去管理不同环境下的日志级别

操作流程:

1/在config配置文件中,给DevelopConfig和ProductConfig设置不同的级别

2/在调用create_app方法的时候,传递对应环境的key值

3/取出对应的环境下的日志级别,将日志级别传递到log_file方法中

当前的一个目录结构:

 1from config import config_dict
 2#定义工厂方法
 3def create_app(config_name):
 4    app = Flask(__name__)
 5
 6    #根据传入的配置类名称,取出对应的配置类
 7    config = config_dict.get(config_name)
 8
 9    #调用日志方法,记录程序运行信息
10    log_file(config.LEVEL_NAME)

config配置文件

 1import logging
 2
 3#设置配置信息(基类配置信息)
 4class Config(object):
 5    ....
 6    #默认日志级别
 7    LEVEL_NAME = logging.DEBUG
 8#开发环境配置信息
 9class DevelopConfig(Config):
10    pass
11
12#生产(线上)环境配置信息
13class ProductConfig(Config):
14    DEBUG = False
15    LEVEL_NAME = logging.ERROR
1import logging
2from logging.handlers import RotatingFileHandler
3def log_file(LEVEL_NAME):
4    # 设置日志的记录等级,常见的有四种,大小关系如下: DEBUG < INFO < WARNING < ERROR
5    logging.basicConfig(level=LEVEL_NAME)  # 调试debug级,一旦设置级别那么大于等于该级别的信息全部都会输出

下面将上面的过程用图片进行一个演示

9.gitkeep忽略日志文件

目的:可以让logs空文件夹能够被提交到git仓库

创建方法:直接在logs文件夹下建立一个空的文件名字为.gitkeep

10.表结构分析

目的:主要是了解xx网站中的主要的7张表之间的关系

注意点:看keynote的图

11.数据库迁移

目的:将模型类迁移成数据库的具体表

操作流程:

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)

12.静态文件集成

目的:为了给用户提供访问页面

操作流程:将status文件夹添加到info里面,然后使用Git管理起来

13.首页显示

目的:在用户访问首页的时候可以给用户

操作步骤:

1/先在info中创建一个template文件夹

2/将status/news中的 index.html拖入到templates/news文件夹中

3/再访问根路径的时候,使用render_template将index.html渲染出来

14.网站logo显示

目的:显示网站的标识,显示在title中

注意点:

1/当浏览器访问每个网站的时候都会自动去请求一个/favicon.ico的接口

2/我们只需要在程序中,写上/favicon.ico的接口,然后返回一张图片即可

3/在flask中需要使用一个方法current_app.send_static_file("文件名")

1/send_static_file("文件1"),该方法会自动去static静态文件夹中寻找文件1

15.图片验证码分析

目的:为了保证注册,登录的用户是个真实的用户在操作,为了去获取短信验证码

注意点:

1/在服务器内部保存图片验证码的时候,前端需要带一个随机字符串(uuid)过来

2/uuid作为key,图片验证码的值作为value存储

16.图片验证码集成

目的:便于程序调用,生成图片验证码

操作流程:

1/在info中创建utils包,将captch导入即可

17.图片验证码视图函数

目的:为了方便前端调用,获取图片验证码

18.图片验证码去重完善

目的: 不能在服务端存储多份图片,容易导致后端的服务器内存不足

操作流程

1/获取参数,cur_id,pre_id

2/调用generator_captch()生成图片验证码

3/存储图片验证码到redis

4/判断是否有上一次图片验证码,如果有则删除

5/返回一张图片,并指定图片格式

优质文章推荐:

公众号使用指南

redis操作命令总结

前端中那些让你头疼的英文单词

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值