zoukankan      html  css  js  c++  java
  • flask综合案例

    一.项目准备

      1.新建项目目录students,并创建虚拟环境

    mkvirtualenv students

      2.安装依赖环境

    pip install flask==0.12.4
    pip install redis
    pip install flask-session
    pip install flask-script
    pip install flask-mysqldb
    pip install flask-sqlalchemy
    pip install flask-migrate
    pip install flask_wtf

      3.在pycharm中打开项目目录编写manage.py启动项目的文件

         (记得配置解释器为我们的虚拟环境解释器)

    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route('/index')
    def index():
        return 'index'
    
    if __name__ == '__main__':
        app.run()

      运行正常说明成功:

      4.创建目录结构:

        mange.py终不能存放大量的开发代码, 在开发中应该体现的是一种分工精神,所以我们可以把flask中各种功能代码进行分类分文件存储.

        创建项目目录结构:

    项目根目录/
    ├── application/            # 项目主要逻辑代码保存目录
    |   ├── settings/           # 项目配置存储目录
    │   │   ├ dev.py            # 开发阶段的配置文件
    │   │   ├ prop.py           # 生产阶段的配置文件
    │   ├── __init__.py         # 项目初始化文件
    ├── manage.py               # 项目的终端管理脚本文件

      5.各配置文件的编写

        配置文件

        settings/__init__.py代码:

    from redis import StrictRedis
    
    class Config(object):
        """项目配置核心类"""
        # 调试模式
        DEBUG = True
    
        # todo 配置日志
        pass
    
        # mysql数据库的配置信息
        SQLALCHEMY_DATABASE_URI = "mysql://root:mysql@127.0.0.1:3306/students?charset=utf8"
        # 动态追踪修改设置,如未设置只会提示警告
        SQLALCHEMY_TRACK_MODIFICATIONS = False
        # 查询时会显示原始SQL语句
        SQLALCHEMY_ECHO= False
    
        # 配置redis
        REDIS_HOST = '127.0.0.1'  # 项目上线以后,这个地址就会被替换成真实IP地址,mysql也是
        REDIS_PORT = 6379
    
        # 设置密钥,可以通过 base64.b64encode(os.urandom(48)) 来生成一个指定长度的随机字符串
        SECRET_KEY = "ghhBljAa0uzw2afLqJOXrukORE4BlkTY/1vaMuDh6opQ3uwGYtsDUyxcH62Aw3ju"
    
        # flask_session的配置信息
        SESSION_TYPE = "redis" # 指定 session 保存到 redis 中
        SESSION_USE_SIGNER = True # 让 cookie 中的 session_id 被加密签名处理
        SESSION_REDIS = StrictRedis(host=REDIS_HOST, port=REDIS_PORT,db=1) # 使用 redis 的实例
        PERMANENT_SESSION_LIFETIME = 24 * 60 * 60 # session 的有效期,单位是秒

        settings/dev.py代码:

    from . import Config
    class DevelopementConfig(Config):
        """开发模式下的配置"""
        # 查询时会显示原始SQL语句
        SQLALCHEMY_ECHO= True

        settings/prop.py代码:

    from . import Config
    class ProductionConfig(Config):
        """生产模式下的配置"""
        DEBUG = False

    二.项目主应用中初始化项目

      1.application/__init__.py文件中,创建flask应用并加载配置

        

    from flask import Flask
    from application.settings.dev import DevelopementConfig
    from application.settings.prop import ProductionConfig
    
    config = {
        "dev": DevelopementConfig,
        "prop": ProductionConfig,
    }
    
    def init_app(config_name):
        """项目的初始化函数"""
        app = Flask(__name__)
    
        # 设置配置类
        Config = config[config_name]
    
        # 加载配置
        app.config.from_object(Config)
    
        return app

      在manage.py 中调用 init_app 函数,启动项目

    from application import init_app
    
    app = init_app("dev")
    
    @app.route("/")
    def index():
        return "index"
    
    if __name__ == '__main__':
        app.run()

      application/__init__.py项目初始化文件中加载redis或者mysql的初始化代码

    from flask import Flask
    from redis import StrictRedis
    from flask_wtf.csrf import CSRFProtect
    from flask_session import Session
    
    from application.settings.dev import DevelopementConfig
    from application.settings.prop import ProductionConfig
    
    config = {
        "dev": DevelopementConfig,
        "prop": ProductionConfig,
    }
    
    # 为了方便redis的连接对象在函数外部可以使用,预先设置一个全局变量,接下来在函数中用于保存redis的连接
    redis_store = None
    
    def init_app(config_name):
        """项目的初始化功能"""
        app = Flask(__name__)
    
        # 设置配置类
        Config = config[config_name]
    
        # 加载配置
        app.config.from_object(Config)
    
        # redis的链接初始化
        global redis_store
        redis_store = StrictRedis(host=Config.REDIS_HOST, port=Config.REDIS_PORT,db=0)
    
        # 开启CSRF防范功能
        CSRFProtect(app)
    
        # 开启session功能
        Session(app)
    
        # TODO 注册蓝图对象到app应用中
    
        return app

        application/__init__.py项目初始化文件初始化mysql

    # from flask import Flask
    # from redis import StrictRedis
    # from flask_wtf.csrf import CSRFProtect
    # from flask_session import Session
    from flask_sqlalchemy import SQLAlchemy
    # 
    # from application.settings.dev import DevelopementConfig
    # from application.settings.prop import ProductionConfig
    # 
    # config = {
    #     "dev": DevelopementConfig,
    #     "prop": ProductionConfig,
    # }
    # 
    # # 为了方便redis的连接对象在函数外部可以使用,预先设置一个全局变量,接下来在函数中用于保存redis的连接
    # redis_store = None
    db = SQLAlchemy()
    # 
    # def init_app(config_name):
    #     """项目的初始化功能"""
    #     app = Flask(__name__)
    # 
    #     # 设置配置类
    #     Config = config[config_name]
    # 
    #     # 加载配置
    #     app.config.from_object(Config)
    # 
    #     # redis的链接初始化
    #     global redis_store
    #     redis_store = StrictRedis(host=Config.REDIS_HOST, port=Config.REDIS_PORT,db=0)
    # 
    #     # 开启CSRF防范功能
    #     CSRFProtect(app)
    # 
    #     # 开启session功能
    #     Session(app)
    # 
        # 配置数据库链接
      # 这个init_app是数据库那个类自身的函数,并不是当前的这个函数
    db.init_app(app) # # # TODO 注册蓝图对象到app应用中 # # return app

      因为前面已经在settings中设置了数据库的配置信息,所以接下来,创建对应的数据库

    create database students charset=utf8;

      2.在manage启动文件中新增关于启动过程中的相关功能(数据库迁移等)

        在项目根目录下`manage.py中设置项目启动程序并调用__init__.py的app

    from application import init_app,db
    from flask_script import Manager
    from flask_migrate import Migrate, MigrateCommand
    
    app = init_app("dev")
    
    # 使用终端脚本工具启动和管理flask
    manager = Manager(app)
    
    # 启用数据迁移工具
    Migrate(app, db)
    # 添加数据迁移的命令到终端脚本工具中
    manager.add_command('db', MigrateCommand)
    
    
    @app.route("/")
    def index():
        return "index"
    
    if __name__ == '__main__':
        manager.run()

     

    三.日志的使用

      Python 自身提供了一个用于记录日志的标准库模块:logging

    FATAL/CRITICAL = 致命的,危险的
    ERROR = 错误
    WARNING = 警告
    INFO = 信息
    DEBUG = 调试
    NOTSET = 没有设置

      application/__init__.py项目初始化文件把日志设置封装成一个函数

    import logging
    from logging.handlers import RotatingFileHandler
    
    # 把日志相关的配置封装成一个日志初始化函数
    def setup_log(Config):
        # 设置日志的记录等级
        logging.basicConfig(level=Config.LOG_LEVEL)  # 调试debug级
        # 创建日志记录器,指明日志保存的路径、每个日志文件的最大大小、保存的日志文件个数上限
        file_log_handler = RotatingFileHandler("logs/log", maxBytes=1024 * 1024 * 300, backupCount=10)
        # 创建日志记录的格式 日志等级 输入日志信息的文件名 行数 日志信息
        formatter = logging.Formatter('%(levelname)s %(filename)s:%(lineno)d %(message)s')
        # 为刚创建的日志记录器设置日志记录格式
        file_log_handler.setFormatter(formatter)
        # 为全局的日志工具对象(flaskapp使用的)添加日志记录器
        logging.getLogger().addHandler(file_log_handler)

        在application/__init__.py项目初始化文件中,在init_app 方法中调用上一步创建的方法,并传入 config_name

     # 启用日志功能
        setup_log(Config)

      在配置文件settings/__init__.py中,设置默认日志等级

    1 class Config(object):
    2     """项目配置核心类"""
    3     # 调试模式
    4     DEBUG = True
    5 
    6     # todo 配置日志
    7     LOG_LEVEL = "DEBUG"

      新增日志以后的项目目录结构(logs这个文件需要手动创建,否则会报错)

    项目根目录/
    ├── docs/                   # 项目开发相关文档
    ├── logs/                   # 项目运行日志保存目录
    |   ├── log                 # 日志文件
    ├── application/            # 项目主要逻辑代码保存目录
    |   ├── settings/           # 项目配置存储目录
    │   │   ├ dev.py            # 开发阶段的配置文件
    │   │   ├ prop.py           # 生产阶段的配置文件
    │   ├── __init__.py         # 项目初始化文件
    ├── manage.py               # 项目的终端管理脚本文件

    四.蓝图创建

      在applications下创建apps目录,apps以后专门用于保存每一个项目的蓝图,

      并在apps创建index蓝图目录,并在__init__.py文件中创建蓝图对象

    from flask import Blueprint
    
    index_blu = Blueprint("index_blu",__name__)

      在index蓝图目录中新增对应的视图文件vies.py,代码:

    from . import index_blu
    
    @index_blu.route("/")
    def index():
        return "首页"

      __init__.py中引入当前蓝图下所有的视图文件

    from flask import Blueprint
    
    index_blu = Blueprint("index_blu",__name__)
    
    from .views import *

      在项目初始化文件application/__init__.py文件中的init_app函数,注册蓝图对象

     # TODO 注册蓝图对象到app应用中
        # 首页模块
        from .apps.index import index_blu
        app.register_blueprint(index_blu,url_prefix='')

      声明了蓝图目录以后的项目目录结构

    项目根目录/
    ├── application/            # 项目主要逻辑代码保存目录
    |   ├── settings/           # 项目配置存储目录
    │   │   ├ dev.py            # 开发阶段的配置文件
    │   │   ├ prop.py           # 生产阶段的配置文件
    │   ├── __init__.py         # 项目初始化文件
    │   ├── statics/            # 保存项目中所有的静态资源文件[img/css/js]
    │   ├── modules/            # 保存项目中所有蓝图的存储目录
    │   │   ├── index           # 蓝图目录
    │   │   │   ├── __init__.py # 蓝图的初始化问年间
    │   │   │   └── views.py    # 蓝图的视图函数文件
    │   │   ├── __init__.py     
    ├── manage.py               # 项目的终端管理脚本文件

        index的模型代码:models.py

    # coding=utf-8
    from application import db
    
    # 创建关系表,不再创建模型,一般用于表与表之间的多对多场景
    """
    表关系变量 = db.Table(
        "关系表表名",
        db.Column('字段名', 字段类型, 字段选项),  # 普通字段
        db.Column("字段名", 字段类型, db.ForeignKey("表名.id")),
        db.Column("字段名", 字段类型, db.ForeignKey("表名.id")),
    )
    """
    achievement = db.Table(
        "achievement",
        db.Column('score', db.Numeric, comment="分数"),
        db.Column('student_id', db.Integer, db.ForeignKey('student.id')),
        db.Column('course_id', db.Integer, db.ForeignKey('course.id'))
    )
    
    class Student(db.Model):
        """学生信息"""
        __tablename__ = "student"
        id = db.Column(db.Integer, primary_key=True, comment="主键ID")
        name = db.Column(db.String(64), index=True, comment="姓名" )
        sex = db.Column(db.Boolean, default=True, comment="性别")
        class_number = db.Column(db.String(32), nullable=True, index=True, comment="班级")
        age = db.Column(db.SmallInteger, comment="年龄")
        description = db.Column(db.Text, comment="个性签名")
        courses = db.relationship(
            'Course', # 模型名称
            secondary=achievement, # 表关系变量
            backref='students', # 当外键反过来获取主键信息时,使用的字段名称,可以自定义,接下来的使用例如: course.students 获取某个课程下所有的学生
            lazy='dynamic'
        )
    
    class Course(db.Model):
        """课程信息"""
        __tablename__ = "course"
        id = db.Column(db.Integer, primary_key=True,comment="主键ID")
        name = db.Column(db.String(64), unique=True,comment="课程名称")

       在主应用中带入模型并迁移数据库

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    #author tom
    from application import init_app, db
    from flask_script import Manager
    from flask_migrate import Migrate,MigrateCommand
    
    app=init_app('dev')
    
    # 使用终端脚本工具启动和管理flask
    manager=Manager(app)
    
    #启用数据迁移工具
    Migrate(app,db)
    #添加数据迁移的命令道终端脚本工具中
    manager.add_command('db',MigrateCommand)
    
    # 导入模型[为了进行数据迁移]
    from application.apps.index import models
    
    
    @app.route('/')
    def index():
        return 'index'
    
    if __name__ == '__main__':
        manager.run()

      迁移数据库:

    #因为上面已经把数据库迁移梦里添加了:
    #所以直接
    
    #初始化
    python manage.py  init
    
    #迁移
    python manage.py  migrate
    
    #生成报表
    python manage.py upgrade

      添加测试数据

    insert into student values 
    (1,"赵华",1,307,22,"对于勤奋的人来说,成功不是偶然;对于懒惰的人来说,失败却是必然。"),
    (2,"程星云",1,301,20,"人生应该如蜡烛一样,从顶燃到底,一直都是光明的。"),
    (3,"陈峰",1,504,21,"在不疯狂,我们就老了,没有记忆怎么祭奠呢?"),
    (4,"苏礼就",1,502,20,"不要为旧的悲伤,浪费新的眼泪。"),
    (5,"张小玉",0,306,18,"没有血和汗水就没有成功的泪水。"),
    (6,"吴杰",1,307,19,"以大多数人的努力程度之低,根本轮不到去拼天赋"),
    (7,"张小辰",0,405,19,"人生的道路有成千上万条, 每一条路上都有它独自的风景。")

       查看数据:在index.view编写视图

    from flask import render_template, request, flash
    
    from application import db
    from . import index_blu
    from .models import Student
    
    @index_blu.route('/')
    def index():
        '''学生列表'''
        student_list=Student.query.all()
        data=[]
        for student in student_list:
            data.append({
                'id': student.id,
                'name':student.name,
                'age':student.age,
                'sex':'' if student.sex else '',
                'description':student.description,
                'class_number':student.class_number,
            })
    
        return render_template('index.html',students=data)

      index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <a href="{{ url_for('index_blu.add') }}">新增学员</a>
        <table border="1" width="1000" align="center">
            <tr>
                <th>id</th>
                <th>姓名</th>
                <th>年龄</th>
                <th>性别</th>
                <th>班级</th>
                <th>个性签名</th>
            </tr>
            {% for student in students  %}
                <tr>
                    <td>{{ student.id }}</td>
                    <td>{{ student.name }}</td>
                    <td>{{ student.age }}</td>
                    <td>{{ student.sex }}</td>
                    <td>{{ student.class_number }}</td>
                    <td>{{ student.description }}</td>
                </tr>
            {% endfor %}
    
        </table>
    
    </body>
    </html>
    View Code

      添加数据:在index.view编写视图

    @index_blu.route('/add',methods=['GET','POST'])
    def add():
        if request.method=='POST':
            #接收数据
            name=request.form.get('username')
            age = int(request.form.get("age"))
            sex = True if request.form.get("sex") == '1' else False
            class_number = request.form.get("class_number")
            description = request.form.get("description")
            #验证数据
            if age<0 or age >120:
                flash('非法年龄数据')
            #入库
            student=Student(name=name,sex=sex,class_number=class_number,description=description)
            try:
                db.session.add(student)
                db.session.commit()
            except Exception as e:
                db.session.rollback()
    
        return render_template('add.html')

      add.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        {% for message in get_flashed_messages() %}
        <span>{{ message }}</span>
        {% endfor %}
        <form action="" method="post">
            <table border="1" witdth="600" align="center">
                <tr>
                    <td>姓名:</td>
                    <td><input type="text" name="username"></td>
                </tr>
                <tr>
                    <td>年龄:</td>
                    <td><input type="text" name="age"></td>
                </tr>
                <tr>
                    <td>性别:</td>
                    <td>
                        <select name="sex">
                            <option value="1"></option>
                            <option value="0"></option>
                        </select>
                    </td>
                </tr>
                <tr>
                    <td>班级:</td>
                    <td><input type="class_number"></td>
                </tr>
                <tr>
                    <td>個性簽名:</td>
                    <td><textarea name="description"></textarea></td>
                </tr>
                <tr>
                    <td>&nbsp;</td>
                    <td>
                        <input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
                        <input type="submit" value="注册">
                    </td>
                </tr>
    
    
            </table>
        </form>
    </body>
    </html>
    View Code

       项目目录结构图:

     

    五。闪现信息[flash]

      使用后,只会出现一次的信息,叫“闪现信息”,用于在验证代码失败,或者一些只需要显示一次性提示的场景。

      使用步骤:

      视图中验证有误,则在显示模板之前设置flash

      flash信息是通过session保存,也是从session中获取的,所以要设置app.config["SECRE_KEY"]

    # 视图函数代码
    from flask import flash
    
    flash("对不起,您尚未登录,请登录!")

      模板代码:

    # 模板代码
    {% for message in get_flashed_messages() %}
        <span>{{message}}</span>
    {% endfor %}
  • 相关阅读:
    软工实践寒假作业(2/2)
    软工实践寒假作业(1/2)
    个人技术总结——关于springboot的定时任务框架quartz
    个人作业——软件工程实践总结&个人技术博客
    个人作业——软件评测
    结对第二次作业——某次疫情统计可视化的实现
    结对第一次 — 疫情统计可视化(原型设计)
    软工实践寒假作业(2/2)
    软工实践寒假作业(1/2)
    个人作业——软件工程实践总结&个人技术博客
  • 原文地址:https://www.cnblogs.com/tjp40922/p/10686333.html
Copyright © 2011-2022 走看看