flask——demo

综合案例:学生成绩管理

新建项目目录stud, 并创建虚拟环境stud

    mkvirtualenv stud -p python3

安装开发中使用的依赖模块

pip install flask==0.12.4 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install redis==3.2.1 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install flask-session==0.3.1 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install flask-script==2.0.6 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install flask-mysqldb==0.2.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install flask-sqlalchemy -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install flask-migrate==2.5.2 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install flask_wtf==0.14.2 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install Faker==2.0.0 -i https://pypi.tuna.tsinghua.edu.cn/simple

在pycharm中打开项目目录,设置虚拟环境以后,编写manage.py启动项目的文件

mkdir ~/Desktop/stud

创建 manage.py 文件

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return 'index'

if __name__ == '__main__':
    app.run()

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

创建项目目录结构:

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

配置文件

settings/__init__.py代码:

from redis import Redis
class Config():
    """配置类"""
    """调试模式"""
    DEBUG = True

    """密钥"""
    # 密钥,可以通过 base64.b64encode(os.urandom(48)) 来生成一个指定长度的随机字符串
    SECRET_KEY = "ghhBljAa0uzw2afLqJOXrukORE4BlkTY/1vaMuDh6opQ3uwGYtsDUyxcH62Aw3ju"

    """日志管理"""

    """数据库"""
    # mysql数据库的配置信息
    SQLALCHEMY_DATABASE_URI = ""
    # 动态追踪修改设置,如未设置只会提示警告
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    # 查询时会显示原始SQL语句
    SQLALCHEMY_ECHO= False

    """redis"""
    REDIS_HOST = '127.0.0.1'  # 项目上线以后,这个地址就会被替换成真实IP地址,mysql也是
    REDIS_PORT = 6379

    """session"""
    SESSION_TYPE = "redis" # 指定 session 保存到 redis 中
    SESSION_USE_SIGNER = True # 让 cookie 中的 session_id 被加密签名处理
    SESSION_REDIS = Redis(host=REDIS_HOST, port=REDIS_PORT,db=1) # 使用 redis 的实例
    PERMANENT_SESSION_LIFETIME = 24 * 60 * 60 # session_id的有效期,单位是秒

settings/dev.py代码:

from . import Config
class DevConfig(Config):
    """开发模式下的配置"""
    # 查询时会显示原始SQL语句
    SQLALCHEMY_ECHO= True
    SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/student?charset=utf8"

settings/prod.py代码:

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

项目主应用中初始化项目

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

from flask import Flask
from application.settings.dev import Devonfig
from application.settings.prod import ProdConfig

def init_app(config_name):
    """项目初始化函数"""
    app = Flask(__name__)
    # 加载配置
    config = {
        "dev": DevConfig,
        "prod": ProdConfig
    }
    app.config.from_object(config.get(model))
    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 Devonfig
from application.settings.prod import ProdConfig

config_dict = {
    "dev": DevConfig,
    "prod": ProdConfig,
}

# 为了方便redis的连接对象在函数外部可以使用,预先设置一个全局变量,接下来在函数中用于保存redis的连接
redis_store = None

def init_app(config_name):
    """项目的初始化功能"""
    app = Flask(__name__)

    # 设置配置类
    Config = config.get(config_name)

    # 加载配置
    app.config.from_object(Config)

    # redis的链接初始化
    app.redis = Redis(host=Config.REDIS_HOST, port=Config.REDIS_PORT,db=0)

    # 开启CSRF防范功能
    CSRFProtect(app)

    # 开启session功能
    Session(app)

    # TODO 注册蓝图对象到app应用中

    return app

调整redis的加载,把redis的配置信息和初始化代码进行分离

新建文件application/utils/helper.py,helper.py后面用于保存一些自己封装的工具助手函数.代码:

from redis import Redis
def get_redis_connection(**option):
    return Redis(host=option.get("host"), port=option.get("port"), db=option.get("db"))

application/settings/__init__.py,代码:

from redis import Redis
from application.utils.helper import get_redis_connection
import os

class Config(object):
    
    """调试模式"""
    DEBUG = True
    """密钥"""
    # 密钥,可以通过 base64.b64encode(os.urandom(48)) 来生成一个指定长度的随机字符串
    SECRET_KEY = "ghhBljAa0uzw2afLqJOXrukORE4BlkTY/1vaMuDh6opQ3uwGYtsDUyxcH62Aw3ju"

    """日志管理"""

    """数据库"""
    # mysql数据库的配置信息
    SQLALCHEMY_DATABASE_URI = ""
    # 动态追踪修改设置,如未设置只会提示警告
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    # 查询时会显示原始SQL语句
    SQLALCHEMY_ECHO = False

    """redis配置"""
    REDIS = {
        'default':{
            'host':'127.0.0.1',  # 项目上线以后,这个地址就会被替换成真实IP地址,mysql也是
            'port':6379,
            'db': 0
        },
        'session':{
            'host': '127.0.0.1',  # 项目上线以后,这个地址就会被替换成真实IP地址,mysql也是
            'port': 6379,
            'db': 1
        }
    }

    """session"""
    SESSION_TYPE = "redis" # 指定 session 保存到 redis 中
    SESSION_USE_SIGNER = True # 让 cookie 中的 session_id 被加密签名处理
    SESSION_REDIS = get_redis_connection(**REDIS["session"])  # 使用 redis 的实例
    PERMANENT_SESSION_LIFETIME = 24 * 60 * 60 # session_id的有效期,单位是秒

在主应用application的初始化__init__py_中使用redis可以如下使用:

mange.py代码:

from flask import Flask
from application.settings.dev import DevConfig
from application.settings.prod import ProdConfig
from flask_wtf import CSRFProtect
from flask_session import Session
from application.utils.flask_redis import get_redis_connection

def init_app(config_name):
    """项目初始化函数"""

    config_dict = {
        "dev": DevConfig,
        "prod": ProdConfig,
    }

    Config = config_dict.get(config_name)

    # 初始化框架
    app = Flask(__name__)
    app.config.from_object(Config)

    # 初始化数据库

    # 初始化redis
    app.redis = get_redis_connection(Config.REDIS["default"])

    # 初始化CSRF
    CSRFProtect(app)

    # 初始化session
    Session()

    return app

manage.py,代码:

from application import init_app

app = init_app("dev")

@app.route('/')
def index():
    app.redis.set("mobile","123456")
    return 'index'

if __name__ == '__main__':
    app.run()

增加数据库配置

from flask import Flask
from application.settings.dev import DevConfig
from application.settings.prod import ProdConfig
from flask_wtf import CSRFProtect
from flask_session import Session
from application.utils.flask_redis import get_redis_connection
from flask_sqlalchemy import SQLAlchemy

def init_app(config_name):
    """项目初始化函数"""

    config_dict = {
        "dev": DevConfig,
        "prod": ProdConfig,
    }

    Config = config_dict.get(config_name)

    # 初始化框架
    app = Flask(__name__)
    app.config.from_object(Config)

    # 初始化数据库
    app.db = SQLAlchemy(app)

    # 初始化redis
    app.redis = get_redis_connection(Config.REDIS["default"])

    # 初始化CSRF
    CSRFProtect(app)

    # 初始化session
    Session()

    return app

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

create database student charset=utf8mb4;

1559267034887

在manage启动文件中新增关于启动过程中的相关功能

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

from flask import Flask
from application.settings.dev import DevConfig
from application.settings.prod import ProdConfig
from flask_wtf import CSRFProtect
from flask_session import Session
from application.utils.flask_redis import get_redis_connection
from flask_sqlalchemy import SQLAlchemy
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand

db = SQLAlchemy()

def init_app(config_name):
    """项目初始化函数"""

    config_dict = {
        "dev": DevConfig,
        "prod": ProdConfig,
    }

    Config = config_dict.get(config_name)

    # 初始化框架
    app = Flask(__name__)
    app.config.from_object(Config)

    # 初始化数据库
    db.init_app(app)

    # 初始化redis
    app.redis = get_redis_connection(Config.REDIS["default"])

    # 初始化CSRF
    CSRFProtect(app)

    # 初始化session
    Session()

    # 初始化终端脚本
    app.manage = Manager(app)

    # 初始化数据迁移
    Migrate(app,db)
    app.manage.add_command("db",MigrateCommand)

    return app

在mange.py中启动项目

from application import init_app
app = init_app("dev")

@app.route('/')
def index():
    app.redis.set("mobile","123456")
    return 'index'

if __name__ == '__main__':
    app.manage.run()

日志

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

日志的等级

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

把日志设置封装成一个函数,写在utils目录下

import logging
from logging.handlers import RotatingFileHandler

def setup_log(Config):
    # 设置日志的记录等级
    logging.basicConfig(level=Config.LOG_LEVEL)  # 调试debug级
    # 创建日志记录器,指明日志保存的路径、每个日志文件的最大大小、保存的日志文件个数上限
    file_log_handler = RotatingFileHandler(
        Config.LOG_FILE_PATH,
        maxBytes=Config.LOG_FILE_SIZE, backupCount=Config.LOG_FILE_NUMBER)
    # 创建日志记录的格式 日志等级 输入日志信息的文件名 行数 日志信息
    formatter = logging.Formatter('%(levelname)s %(asctime)s %(filename)s:%(lineno)d %(message)s')
    # 为刚创建的日志记录器设置日志记录格式
    file_log_handler.setFormatter(formatter)
    # 为全局的日志工具对象(flaskapp使用的)添加日志记录器
    logging.getLogger().addHandler(file_log_handler)

init_app 方法中调用上一步创建的方法,并传入 config_name

application/__init__.py,代码:

import logging
from flask import Flask
from application.settings.dev import DevConfig
from application.settings.prod import ProdConfig
from flask_wtf.csrf import CSRFProtect
from flask_session import Session
from application.utils.helper import get_redis_connection
from flask_sqlalchemy import SQLAlchemy
from flask_script import Manager,Command
from flask_migrate import Migrate,MigrateCommand
from application.utils.log import setup_log
config_dict = {
    "dev": DevConfig,
    "prod": ProdConfig,
}

db = SQLAlchemy()

def init_app(config_name):
    """项目初始化函数"""
    # 创建app应用
    app = Flask(__name__)
    # 根据选项获取配置类
    Config = config_dict.get(config_name)
    # 加载配置
    app.config.from_object(Config)

    # 日志初始化
    setup_log(Config)
    app.log = logging.getLogger()

    # redis数据库
    app.redis = get_redis_connection(Config.REDIS["default"])

    # 初始化数据库
    db.init_app(app)

    # 开启CSRF防范功能
    CSRFProtect(app)

    # 开启session功能
    Session(app)

    # 初始化终端脚本
    app.manage = Manager(app)

    # 初始化数据迁移
    Migrate(app,db)
    app.manage.add_command("db",MigrateCommand)

    # TODO 注册蓝图对象到app应用中

    return app

在配置文件settings/__init__.py中,设置默认日志等级并设置当前项目主应用目录作为一个配置常量

from redis import Redis
from application.utils.flask_redis import get_redis_connection
class Config():
    """配置类"""
    # 当前项目主应用目录
    BASE_DIR = os.path.dirname( os.path.dirname( os.path.abspath(__file__) ) )
    
    """调试模式"""
    DEBUG = True

    """密钥"""
    # 密钥,可以通过 base64.b64encode(os.urandom(48)) 来生成一个指定长度的随机字符串
    SECRET_KEY = "ghhBljAa0uzw2afLqJOXrukORE4BlkTY/1vaMuDh6opQ3uwGYtsDUyxcH62Aw3ju"

    """日志管理"""
    LOG_LEVEL = "DEBUG"
    LOG_FILE_PATH = "logs/log"
    LOG_FILE_SIZE = 1024 * 1024 * 300
    LOG_FILE_NUMBER = 10

    """数据库"""
    # mysql数据库的配置信息
    SQLALCHEMY_DATABASE_URI = ""
    # 动态追踪修改设置,如未设置只会提示警告
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    # 查询时会显示原始SQL语句
    SQLALCHEMY_ECHO= False

    """redis配置"""
    REDIS = {
        'default':{
            'host':'127.0.0.1',  # 项目上线以后,这个地址就会被替换成真实IP地址,mysql也是
            'port':6379,
            'db': 0
        },
        'session':{
            'host': '127.0.0.1',  # 项目上线以后,这个地址就会被替换成真实IP地址,mysql也是
            'port': 6379,
            'db': 1
        }
    }

    """session"""
    SESSION_TYPE = "redis" # 指定 session 保存到 redis 中
    SESSION_USE_SIGNER = True # 让 cookie 中的 session_id 被加密签名处理
    SESSION_REDIS = get_redis_connection(**REDIS["session"]) # 使用 redis 的实例
    PERMANENT_SESSION_LIFETIME = 24 * 60 * 60 # session_id的有效期,单位是秒

项目的生产环境配置文件中,设置默认的日志等级为“INFO”或者“WARNING”

如果要在manage.py测试日志功能,可以使用以下代码:

from application import init_app
app = init_app("prod")

@app.route('/')
def index():
    try:
        1 / 0
    except:
        app.log.error("程序出错!")
    app.redis.set("mobile","123456")
    return 'index'

if __name__ == '__main__':
    app.manage.run()

新增日志以后的项目目录结构

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

经过上面的改造,我们接下来就可以开始创建蓝图了。

创建蓝图目录

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

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

from flask import Blueprint

home_blu = Blueprint("home",__name__)

from .views import *

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

from . import home_blu

@home_blu.route("/")
def index():
    return "hemo"

application/__init__.py的init_app函数中,引入home_blu蓝图下视图文件

import logging
import sys
import os

def init_app(config):
    """项目初始化函数"""

		# ....
    
    # 配置视图的存储目录为默认导包路径
    sys.path.insert(0, Config.BASE_DIR)
    sys.path.insert(0, os.path.join(Config.BASE_DIR, "apps"))
    
    # 蓝图注册
    from home import home_blu
    app.register_blueprint(home_blu, prefix="")

    return app

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

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

模型创建

通行也可以通过不同的蓝图进行分开存放.我们把之前声明的课程\学生\成绩关系\老师的模型提取过来

from application import db

"""
# 创建关系表,不再创建模型,一般用于表与表之间的多对多场景

表关系变量 = db.Table(
    "关系表表名",
    db.Column('字段名', 字段类型, 字段选项),  # 普通字段
    db.Column("字段名", 字段类型, db.ForeignKey("表名.id")),
    db.Column("字段名", 字段类型, db.ForeignKey("表名.id")),
)
"""
achievement = db.Table(
    "tb_achievement",
    db.Column('score', db.Numeric, comment="分数"),
    db.Column('student_id', db.Integer, db.ForeignKey('tb_student.id')),
    db.Column('course_id', db.Integer, db.ForeignKey('tb_course.id'))
)

"""
class Achievement(db.Model):
	  id = db.Column(db.Integer, primary_key=True, comment="主键ID")
    db.Column('score', db.Numeric, comment="分数"),
    student_id = db.Column(db.Integer, db.ForeignKey('tb_student.id'))
    course_id = db.Column(db.Integer, db.ForeignKey('tb_course.id'))
"""

class Student(db.Model):
    """学生信息"""
    __tablename__ = "tb_student"
    # comment 表示 字段的注释
    id = db.Column(db.Integer, primary_key=True, comment="主键ID")
    # index 设置普通索引,目的: 加快查询数据的速度
    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="个性签名")
    # score = db.relationship('Achievement', backref='student', lazy='dynamic')

    # 并非表字段,而是模型的属性
    courses = db.relationship(
        'Course', # 模型名称
        secondary=achievement, # 表关系变量
        backref='students', # 当外键反过来获取主键信息时,使用的字段名称,可以自定义,接下来的使用例如: course.students 获取某个课程下所有的学生
        lazy='dynamic'
    )


class Course(db.Model):
    """课程信息"""
    __tablename__ = "tb_course"
    id = db.Column(db.Integer, primary_key=True, comment="主键ID")
    name = db.Column(db.String(64), unique=True, comment="课程名称")
    # score = db.relationship('Achievement', backref='course', lazy='dynamic')

注册蓝图下面的模型到manage.py文件中

from application import app

# 注册模型
from home.models import *

if __name__ == '__main__':
    app.manager.run()

模型的数据迁移

python manage.py db init  # 项目刚创建时进行初始化
python manage.py db migrate -m '创建基本数据库'
python manage.py db upgrade

添加测试数据

application/utils/command.py里面创建一个生成测试数据的自定义命令

from flask_script import Command
from home.models import Student
from faker import Faker
from application import db
import random

class CreateDataCommand(Command):
    """生成学生测试数据"""
    def run(self):
        faker = Faker(locale="zh_CN")
        data = []
        num = 0
        for _ in range(100):
            sex = random.randint(0, 1)
            try:
                student = Student(
                    name=faker.name_female() if sex else faker.name_male(),
                    sex=not not sex,
                    description=faker.sentence(nb_words=6, variable_nb_words=True, ext_word_list=None),
                    age=random.randint(13, 28)
                )
                db.session.add(student)
                db.session.commit()
                num+=1
            except:
                pass

        print("本次共生成了%s个数据" % num)

在manage.py中注册命令

from application.utils.command import CreateDataCommand
app.manage.add_command("test",CreateDataCommand() )

在终端下,执行以下命令即可创建100个用户

 python manage.py test

上面有了学生信息以后,我们可以在index蓝图下,创建基于前后端不分离模式的6个视图:

from . import home_blu

@home_blu.route("/",methods=["get"])
def index():
    return "学生列表页面"

@home_blu.route("/add",methods=["get"])
def add():
    return "添加学生信息页面"

@home_blu.route("/create",methods=["post"])
def create():
    return "添加学生功能"

@home_blu.route("/edit",methods=["get"])
def edit():
    return "编辑学生信息页面"

@home_blu.route("/update",methods=["put"])
def update():
    return "更新学生信息功能"

@home_blu.route("/delete",methods=["delete"])
def delete():
    return "删除学生信息功能"

在蓝图中设置当前蓝图的模板和静态目录,在application/apps/home目录下创建templates和static目录,

并修改home蓝图下的__init__.py,代码:

from flask import Blueprint

home_blu = Blueprint("home",__name__, static_folder="static", static_url_path="/statics", template_folder="templates")

from .views import *

完成学生信息列表页面

application/apps/home/views.py,视图代码:

from . import index_blu
from flask import render_template
from .models import Student
@index_blu.route("/",methods=["get"])
def index():
    # 查询学生信息
    student_list = Student.query.all()
    return render_template("list.html",**{
        "student_list":student_list,
    })

@index_blu.route("/add",methods=["get"])
def add():
    return "添加学生信息页面"

@index_blu.route("/create",methods=["post"])
def create():
    return "添加学生功能"

@index_blu.route("/edit",methods=["get"])
def edit():
    return "编辑学生信息页面"

@index_blu.route("/update",methods=["put"])
def update():
    return "更新学生信息功能"

@index_blu.route("/delete",methods=["delete"])
def delete():
    return "删除学生信息功能"

模板代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/statics/list.css">
</head>
<body>
    <h1>学生成绩信息录入系统</h1>
    <table>
        <tr>
            <td><a href="/add">添加信息</a></td>
        </tr>
        <tr>
            <th>ID</th>
            <th>姓名</th>
            <th>年龄</th>
            <th>性别</th>
            <th>操作</th>
        </tr>
        {% for student in student_list %}
        <tr>
            <td>{{ student.id }}</td>
            <td>{{ student.name }}</td>
            <td>{{ student.age }}</td>
            <td>{{ "男" if student.sex else "女" }}</td>
            <td>
                <a href="/edit/{{ student.id }}">编辑</a>
                &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                <a href="/delete/{{ student.id }}">删除</a>
            </td>
        </tr>
        {% endfor %}

    </table>
</body>
</html>

在home/static/list.css,代码:

    body{
        background-color: #eee;
        color: #333;
    }
    h1{
        font-weight: normal;
        text-align: center;
    }
    table{
        border-collapse: collapse;
        border: 1px solid red;
        margin: 30px auto;
    }
    tr{
        height: 32px;
        line-height: 32px;
    }
    td,th{
        font-weight: normal;
        text-align: center;
        padding: 4px 7px;
        font-size: 14px;
        border: 1px solid red;
        width: 120px;
    }

添加学生信息

home/add.html,基本模板:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
    body{
        background-color: #eee;
        color: #333;
    }
    h1{
        font-weight: normal;
        text-align: center;
    }
    table{
        border-collapse: collapse;
        border: 1px solid red;
        margin: 30px auto;
    }
    tr{
        height: 32px;
        line-height: 32px;
    }
    td,th{
        font-weight: normal;
        text-align: center;
        padding: 4px 7px;
        font-size: 14px;
        border: 1px solid red;
        width: 120px;
    }
    input[type=text],
    textarea{
        width: 100%;
        background-color: transparent;
        border: none;
        height: 32px;
        outline: none;
    }
    input[type=submit]{
        width: 120px;
        height: 32px;
        font-size: 17px;
        color: #333;
        text-align: center;
        background: none;
        border: none;
        outline: none;
        cursor: pointer;
    }
    </style>
</head>
<body>
    <h1>学生成绩信息录入系统</h1>
    <form action="/create" method="post">
        <table>
            <tr>
                <td>姓名</td>
                <td><input type="text" name="name"></td>
            </tr>
            <tr>
                <td>年龄</td>
                <td><input type="text" name="age"></td>
            </tr>
            <tr>
                <td>性别</td>
                <td>
                    <label><input type="radio" name="sex" value="0">&nbsp;&nbsp;女</label>
                    <label><input type="radio" name="sex" value="1">&nbsp;&nbsp;男</label>
                </td>
            </tr>
            <tr>
                <td>个性签名</td>
                <td>
                    <input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
                    <textarea name="description"></textarea>
                </td>
            </tr>
            <tr>
                <td colspan="2"><input type="submit" value="提交"></td>
            </tr>
        </table>

    </form>
</body>
</html>

添加数据提交后端

from . import home_blu
from .models import Student
from flask import render_template,request, redirect,url_for
from application import db
@home_blu.route("/",methods=["get"])
def index():
    student_list = Student.query.all()

    return render_template("list.html", **{
        "student_list": student_list,
    })

@home_blu.route("/add",methods=["get"])
def add():
    return render_template("add.html")

@home_blu.route("/create",methods=["post"])
def create():
    # 接受数据
    try:
        name = str( request.form.get("name") )
        age = int( request.form.get("age") )
        sex = bool( int( request.form.get("sex") ) )
    except:
        return redirect(url_for("home.add"))

    # 校验数据
    res = Student.query.filter(Student.name==name).first()
    if res:
        # 返回添加数据的表单视图中
        return redirect( url_for("home.add") )

    # 添加数据
    try:
        student = Student(name=name, age=age, sex=sex)
        db.session.add(student)
        db.session.commit()
        # 返回列表数据视图中
        return redirect( url_for("home.index") )
    except:
        # 返回添加数据的表单视图中
        return redirect(url_for("home.add"))

@home_blu.route("/edit",methods=["get"])
def edit():
    return "编辑学生信息页面"

@home_blu.route("/update",methods=["put"])
def update():
    return "更新学生信息功能"

@home_blu.route("/delete",methods=["delete"])
def delete():
    return "删除学生信息功能"

闪现信息[flash]

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

使用步骤:

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

# 视图函数代码
from flask import flash

flash("对不起,您尚未登录,请登录!")

模板代码:

# 模板代码
{% for message in get_flashed_messages() %}
	<span>{{message}}</span>
{% endfor %}

使用闪现信息显示错误提示

视图:

from . import home_blu
from .models import Student
from flask import render_template,request, redirect,url_for,flash
from application import db

@home_blu.route("/",methods=["get"])
def index():
    student_list = Student.query.all()

    return render_template("list.html", **{
        "student_list": student_list,
    })

@home_blu.route("/add",methods=["get"])
def add():
    return render_template("add.html")

@home_blu.route("/create",methods=["post"])
def create():
    # 接受数据
    try:
        name = str( request.form.get("name") )
        age = int( request.form.get("age") )
        sex = bool( int( request.form.get("sex") ) )
    except:
        flash("对不起,数据格式有误!")
        return redirect(url_for("home.add"))

    # 校验数据
    res = Student.query.filter(Student.name==name).first()
    if res:
        # 返回添加数据的表单视图中
        flash("对不起,当前用户已经注册!")
        return redirect( url_for("home.add") )

    # 添加数据
    try:
        student = Student(name=name, age=age, sex=sex)
        db.session.add(student)
        db.session.commit()
        # 返回列表数据视图中
        return redirect( url_for("home.index") )
    except:
        flash("对不起,添加用户失败!")
        # 返回添加数据的表单视图中
        return redirect(url_for("home.add"))

@home_blu.route("/edit",methods=["get"])
def edit():
    return "编辑学生信息页面"

@home_blu.route("/update",methods=["put"])
def update():
    return "更新学生信息功能"

@home_blu.route("/delete",methods=["delete"])
def delete():
    return "删除学生信息功能"

add.html,模板:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
    body{
        background-color: #eee;
        color: #333;
    }
    h1{
        font-weight: normal;
        text-align: center;
    }
    table{
        border-collapse: collapse;
        border: 1px solid red;
        margin: 30px auto;
    }
    tr{
        height: 32px;
        line-height: 32px;
    }
    td,th{
        font-weight: normal;
        text-align: center;
        padding: 4px 7px;
        font-size: 14px;
        border: 1px solid red;
        width: 120px;
    }
    input[type=text],
    textarea{
        width: 100%;
        background-color: transparent;
        border: none;
        height: 32px;
        outline: none;
    }
    input[type=submit]{
        width: 120px;
        height: 32px;
        font-size: 17px;
        color: #333;
        text-align: center;
        background: none;
        border: none;
        outline: none;
        cursor: pointer;
    }
    </style>
</head>
<body>
    <h1>学生成绩信息录入系统</h1>
    <form action="/create" method="post">
        <table>
            <tr>
                <td>姓名</td>
                <td><input type="text" name="name"></td>
            </tr>
            <tr>
                <td>年龄</td>
                <td><input type="text" name="age"></td>
            </tr>
            <tr>
                <td>性别</td>
                <td>
                    <label><input type="radio" name="sex" value="0">&nbsp;&nbsp;女</label>
                    <label><input type="radio" name="sex" value="1">&nbsp;&nbsp;男</label>
                </td>
            </tr>
            <tr>
                <td>个性签名</td>
                <td>
                    <input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
                    <textarea name="description"></textarea>
                </td>
            </tr>
            <tr>
                <td colspan="2"><input type="submit" value="提交"></td>
            </tr>
        </table>
    </form>
    <script>
        {% for message in get_flashed_messages() %}
        alert("{{ message }}");
        {% endfor %}
    </script>
</body>
</html>
posted @ 2021-08-22 18:03  啦啦la  阅读(290)  评论(0)    收藏  举报