专栏首页小闫笔记经典案例之某新闻网站的实现

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

1.项目介绍

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

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

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

数据存储:redis + mysql

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

部署:基于Ubuntu16.04

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

2.配置文件抽取

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

操作流程:

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
}

3.初始化信息抽取

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

操作流程:

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)

4.视图函数抽取

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

操作流程:

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输出更加的美观,便于查看;但是在日志中,两种方法的效果是完全一样的,没有任何不同

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方法中调用即可

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)

8.日志配置抽取

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

操作流程:

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级,一旦设置级别那么大于等于该级别的信息全部都会输出

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

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操作命令总结

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

本文分享自微信公众号 - 全栈技术精选(Pythonnote),作者:小闫同学啊

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-12-30

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Flask阶段(一)代码

    小闫同学啊
  • Git管理源代码

    app.config["SECRET_KEY"] = "fdfdfdfd"app.config["SESSION_TYPE"] = "redis" #指定ses...

    小闫同学啊
  • 团队开发注意事项

    因为是多人同时开发一个项目,每个人有自己的模块,但是对于一些公共文件的修改很有可能出现冲突。

    小闫同学啊
  • MySQL架构组成、物理文件组成

    MySQL经过多年的改进和完善之后,已经基本具备了所有通用数据库管理系统所需要的相关功能。

    L宝宝聊IT
  • 建造适于业务分析的日志数据系统

    现在“大数据”非常的火。我们看到有各种相关的技术文章和软件推出,但是,当我们面对真正日常的业务时,却往往觉得无法利用上“大数据”。初步想来,好像原因有两个:第一...

    韩伟
  • 数据库MySQL-复制

    当我们因为误操作修改了数据库中的数据, 同时有没有备份可以恢复时, 我们就可以通过分析二进制日志, 对日志中记录的数据修改操作做反向处理的方式来达到恢复数据的目...

    cwl_java
  • Grafana Loki 设计文档

    本文的目的是为了解释 Grafana Loki 服务的设计动机。本文档并不会深入描述设计的所有细节,但希望能够对一些关键点进行说明,使我们能够提前发现任何明显...

    我是阳明
  • 数据库的“黑匣子”--故障诊断日志基础

    相信大家都知道,当飞机发生事故后,人们进行搜救的时候,总是会寻找一个东西---被誉为空难“见证人”的黑匣子。它可以给调查人员提供证据,帮组他们了解事故的真相。 ...

    TeacherWhat
  • 性能监控之JMeter分布式压测轻量日志解决方案

    在前文中我们已经介绍了使用JMeter非GUI模式进行压测的时候,我们可以使用 InfluxDB+Grafana进行实时性能测试结果监控,也可以用 Tegraf...

    高楼Zee
  • MySQL日志管理

    一、日志类型: MySQL有几个不同的日志文件,可以帮助你找出mysqld内部发生的事情: 日志文件记入文件中的信息类型错误日志记录启动、运行或停止时出现的问题...

    小小科

扫码关注云+社区

领取腾讯云代金券