Flask-蓝图、模型与CodeFirst
一、应用、蓝图与视图函数
结构,如图:
Flask最上层是
app核心对象
,在这个核心对象上可以插入很多蓝图,这个蓝图是不能单独存在的,必须将app作为插板插入app ,在每一个蓝图上,可以注册很多静态文件,视图函数,模板 ,一个业务模块可以做为一个蓝图,比如book,之前的book.py 放到了app/web/路径下,就是考虑到了蓝图,app属于是整个Flask应用层,web属于是蓝图一些初始化操作应该放入到
__init__
文件中,比如Flask的核心应用app初始化对象,应该放入到在应用层级app包的__init__.py
中 ,而蓝图的初始化应该放入到蓝图层的web包__init__.py
中,如图:Flask的核心应用app初始化对象文件
app/__init__.py
# -*- coding: utf-8 -*-
from flask import Flask
def create_app():
app = Flask(__name__)
app.config.from_object('config')
# 要返回回去
return app
- 此时在主文件中
# -*- coding: utf-8 -*-
from app import create_app
app = create_app()
if __name__ == '__main__':
app.run(debug=app.config['DEBUG'])
二、用蓝图注册视图函数
- 在蓝图中注册试图函数,在
app/web/book.py
中,记得导入Blueprint
# -*- coding: utf-8 -*-
from flask import jsonify, Blueprint
from helper import is_isbn_key
from ShanqiuBook import ShanqiuBook
# 蓝图 blueprint,进行初始化,蓝图的名字和参数为蓝图所在的模块名一般用__name__
web = Blueprint ('web',__name__)
# 此时这里用的就是web了
@web.route('/book/search/<q>/<page>')
def hello(q,page):
is_or_key = is_isbn_key(q)
if is_or_key == 'isbn':
result = ShanqiuBook.search_by_isbn(q)
else:
result = ShanqiuBook.search_by_keyword(q)
return jsonify(result)
- 在蓝图中注册了试图函数,还需要把蓝图插入到app中,
app/__init__.py
# -*- coding: utf-8 -*-
from flask import Flask
def create_app():
app = Flask(__name__)
app.config.from_object('config')
# 调用一下就可以
register_blueprint(app)
return app
# 通过这个方法插入到app中
def register_blueprint(app):
from app.web.book import web
# 注册这个蓝图对象
app.register_blueprint(web)
三、单蓝图多模块拆分视图函数
- 蓝图,就是为了分模块的,比如一个web系统就是属于一个web模块,一个移动端使用的api就是一个api模块,而我们这里的book,user等不同类别的py文件,要是每一个都注册一个蓝图的话就有点小题大作了,所以要进行单蓝图
- 在一个模块(web)的初始文件中定义蓝图对象,然后这个模块中的其他的py文件引用的就是这一个蓝图对象来注册路由函数,
- 在app/web/book.py文件中
# -*- coding: utf-8 -*-
from flask import jsonify, Blueprint
from helper import is_isbn_key
from ShanqiuBook import ShanqiuBook
# 导入web模块
from . import web
@web.route('/book/search/<q>/<page>')
def hello(q,page):
# 调用方法判断用户是根据什么查的
is_or_key = is_isbn_key(q)
if is_or_key == 'isbn':
result = ShanqiuBook.search_by_isbn(q)
else:
result = ShanqiuBook.search_by_keyword(q)
return jsonify(result)
- 这里先建立一个伪代码user.py,为了多一个模块进行演示
# -*- coding: utf-8 -*-
# 导入web模块
from . import web
@web.route("/user/login")
def login():
return "success"
- 此时在
app/web/__init__.py
文件中,定义这个蓝图对象
# -*- coding: utf-8 -*-
# 蓝图 blueprint,进行初始化
from flask import Blueprint
web = Blueprint ('web',__name__)
# 这两个导入之后就可以成功的运行对应模块中相关的代码,注意这个位置,这蓝图实例化之后
from app.web import book
from app.web import user
四、Request对象
- 在app/web/book.py文件中,定义的url请求是
/book/search/<q>/<page>
这种格式的,Flask会将<>里的值自动映射成视图函数方法的参数,但是这种格式用着不爽,要把用户输入的参数作为请求参数传入,这个时候就要使用这种格式了http://127.0.0.1:5000/book/search/?q=金庸&page=1
- 这个该怎么获取值呢,这个时候就用到Flask内置的Request了,通过request对象就可以获取HTTP请求中包含的详细信息了,具体的用法看下面的代码
# -*- coding: utf-8 -*-
# 导入这个request模块,
from flask import jsonify, Blueprint,request
from helper import is_isbn_key
from ShanqiuBook import ShanqiuBook
from . import web
# http://127.0.0.1:5000/book/search/?q=金庸&page=1
@web.route('/book/search/')
def hello():
# 通过Request对象拿到对应值的信息,但是这个并不是py中原始的字典,而是dict的子类immutableDict
q = request.args['q']
page = request.args['page']
# ip = request.remote_addr
# 通过这个方法把它转换为普通的dict
# a = request.args.to_dict()
# print(a)
is_or_key = is_isbn_key(q)
if is_or_key == 'isbn':
result = ShanqiuBook.search_by_isbn(q)
else:
result = ShanqiuBook.search_by_keyword(q)
return jsonify(result)
- Flask的request是基于代理模式实现的,想让request正常使用,必须确保是http请求触发的函数或视图函数中使用
五、WTForms参数验证
- 上面我们把url改了,但是如果用户输入了一些特殊的符号该怎么办?这个时候就要使用到参数验证,而WTForms框架就是一个优秀的参数验证框架,首先在对应的环境中进行安装
(flask--yQglGu4) E:\py\qiyue\flask>pipenv install wtforms
- 这个参数验证写在哪里好呢,直接写在book.py中,这样是最不妥的,为了方便调用,应该写成一个类,所以写在app/forms/book.py文件中
# -*- coding: utf-8 -*-
# 导入需要使用的模块
from wtforms import Form,StringField,IntegerField
from wtforms.validators import Length,NumberRange
class SearchForm(Form):
# 直接调用内置对象
# 参数校验规则:
# 1.定义的属性名q,page要与要校验的参数同名
# 2.根据要传入的参数类型选择不同的Field类进行实例化
# 3.传入一个数组,作为校验规则validators
# 4.可以设置默认值
q = StringField(validators=[DataRequired(),Length(min=1,max=30)])
page = IntegerField(validators=[NumberRange(min=1,max=10)],default=1)
- 此时在app/web/book.py文件中就可以直接调用就行了
# -*- coding: utf-8 -*-
from flask import jsonify, Blueprint,request
from helper import is_isbn_key
from ShanqiuBook import ShanqiuBook
from . import web
# 导入参数校验
from app.forms.book import SearchForm
# http://127.0.0.1:5000/book/search/?q=金庸&page=1
@web.route('/book/search/')
def hello():
# 验证层
# 实例化我们自定义的SearchForm,需要传入一个字典作为要校验的参数
form = SearchForm(request.args)
# validate()方法返回True/False来标示是否校验通过
if form.validate():
# 从form中取出校验后的q与page,并且清除空格
q = form.q.data.strip()
page = form.page.data
is_or_key = is_isbn_key(q)
if is_or_key == 'isbn':
result = ShanqiuBook.search_by_isbn(q)
else:
result = ShanqiuBook.search_by_keyword(q)
return jsonify(result)
else:
return jsonify({'msg':'参数校验失败'})
六、拆分配置文件
- 之前访问数据的时候,count和start都是写死的,现在来进行重构,之前的代码
@classmethod
def search_by_key(cls, q, count=15, start=0):
# count:每页显示的数量
# start:每页的第一条数据的下标
url = cls.search_by_key_url.format(q, count, start)
return HTTP.get(url)
这样写非常的不妥
在视图函数中接收到的参数是page,代码的封装性,我们应该把count和start的计算过程放到ShanqiuBook.py的 search_by_key方法中来写
count的值为了方便日后的管理,这个应该放入到配置文件中,之前的配置文件是config.py,在根目录下,而这个应该放入到app目录下,而关于一些比较隐私的配置信息要妥善处理,所以在app目录下建立两个文件,secure.py用来存放私密的配置信息,setting.py用于存放一些不重要的配置信息,如下
app/secure.py
# -*- coding: utf-8 -*- # 存放比较机密的配置文件,在上传git的时候不应该上传此文件
DEBUG = True
app/setting.py
# -*- coding: utf-8 -*- # 生产环境和开发环境几乎一样的,不怎么机密的配置文件 # 每页显示的数据量
PER_PAGE = 15
start的计算是一个单独的逻辑,应该用封装成一个方法,使用的时候直接调用
# 获取每一页的起始下标
@staticmethod
def calculate_start(page):
# 获取配置信息中的每页显示的数量
return (page -1 ) * current_app.config['PER_PAGE']
重构后的
ShanqiuBook.py
-*- coding: utf-8 -*-
from httper import httper
# 通过这种方式来导入当前的app对象,方便调用配置而文件
from flask import current_app
class ShanqiuBook:
isbn_url = 'http://t.yushu.im/v2/book/search/isbn/{}'
keyword_url = 'http://t.yushu.im/v2/book/search?q={}&count={}&start={}'
@classmethod
def search_by_isbn(cls,isbn):
url = cls.isbn_url.format(isbn)
result = httper.get(url)
return result
@classmethod
def search_by_keyword(cls,keyword,page=1):
# 每页显示的数据(通过这种方式从配置文件中获取到),每一页的起始下标
url = cls.keyword_url.format(keyword,current_app.config['PER_PAGE'],cls.calculate_start(page))
result = httper.get(url)
return result
# 获取每一页的起始下标
@staticmethod
def calculate_start(page):
return (page -1 ) * current_app.config['PER_PAGE']
- 这个时候在
app/__init__.py
文件中把配置文件添加到app中
#-- coding: utf-8 --
from flask import Flask
def create_app():
app = Flask(name)
# app.config.from_object('config')
# 把配置文件装载进来
app.config.from_object('app.secure')
app.config.from_object('app.setting')
register_blueprint(app)
return app
def register_blueprint(app):
from app.web.book import web
app.register_blueprint(web)
七、定义第一个模型类
- 我们现在把文件进行整理,如下:
- 首先在本地创建一个数据库,如下:
在app/models/book.py文件中建立模型,这里使用到sqlalchemy来实现自动化映射,在Flask框架中对这个进行了改良Flask_SQLAlchemy,这个更加人性化,安装
(flask--yQglGu4) E:\py\qiyue\flask>pipenv install flask-sqlalchemy
建立模型,这样就建立好了模型
# -*- coding: utf-8 -*-
# 首先导入
from sqlalchemy import Column,Integer,String
# sqlalchemy,自动化映射
# Flask_SQLAlchemy,这个是Flask封装后的api,更加人性化
class Book():
# 需要把这些属性的默认值写成sqlalchemy提供的固定的类型
# Column()传入参数:数据类型,主键,自增
id = Column(Integer,primary_key=True,autoincrement=True)
# 数据类型,不为空
title = Column(String(50),nullable=False)
author = Column(String(30),default='未名')
binding = Column(String(20))
publisher = Column(String(50))
price = Column(String(20))
pages = Column(Integer)
pubdate = Column(String(20))
# 唯一:unique=True
isbn = Column(String(15),nullable=False,unique=True)
summary = Column(String(1000))
image = Column(String(50))
# 定义一些方法
def sample(self):
pass
八、将模型映射到数据库中
- 在模型类app/models/book.py中引入导入核心对象,并实例化,继承
# -*- coding: utf-8 -*-
from sqlalchemy import Column,Integer,String
# 将模型映射到数据库中
# 首先导入核心的对象
from flask_sqlalchemy import SQLAlchemy
# 初始化
db = SQLAlchemy()
# 继承db.Model
class Book(db.Model):
id = Column(Integer,primary_key=True,autoincrement=True)
title = Column(String(50),nullable=False)
author = Column(String(30),default='未名')
binding = Column(String(20))
publisher = Column(String(50))
price = Column(String(20))
pages = Column(Integer)
pubdate = Column(String(20))
isbn = Column(String(15),nullable=False,unique=True)
summary = Column(String(1000))
image = Column(String(50))
- 在
app/__init__.py
中进行模型与flask关联
# -*- coding: utf-8 -*-
from flask import Flask
# 导入这个db
from app.models.book import db
def create_app():
app = Flask(__name__)
app.config.from_object('app.secure')
app.config.from_object('app.setting')
register_blueprint(app)
# 把这个db和核心对象关联起来了
db.init_app(app)
# 注意这里,这样写的话会报错
db.create_all() # 把所有的数据模型映射到数据库中
return app
def register_blueprint(app):
from app.web.book import web
app.register_blueprint(web)
- 配置数据库连接的配置文件在app/secure.py文件中
# -*- coding: utf-8 -*-
# 存放比较机密的配置文件
DEBUG = True
# 数据库连接url,固定格式
# 要连接的数据库类型,数据库驱动(这里还要进行安装:pipenv install cymysql)
SQLALCHEMY_DATABASE_URI = 'mysql+cymysql://root:123456@localhost:3306/book'
- 之后运行项目,就会创建在指定的数据库中创建一个数据表了,但是运行项目会出现下面的这种错误
'No application found. Either work inside a view function or push'
这个是因为在Flask中,不是实例化了app核心对象,其他代码就可以直接使用,要在上面的第二步的注意事项中` db.create_all()`方法中,把app核心对象传入即可
db.create_all(app=app)
,这样就可以了,在数据库中就可以看到表了
Flask-蓝图、模型与CodeFirst的更多相关文章
- flask 蓝图
转自:http://spacewander.github.io/explore-flask-zh/7-blueprints.html 蓝图 什么是蓝图? 一个蓝图定义了可用于单个应用的视图,模板,静态 ...
- Flask蓝图目录、Flask-SQLAlchemy、Flask-Script、Flask-Migrate
一.Flask蓝图目录 我们之前写的Flask项目都是自己组织的目录结构,其实Flask官方有其推荐的目录结构,以下就是一个符合官方推荐的Flask小型应用的项目结构目录示例,如下: 如图,这就是我们 ...
- Flask 蓝图(Blueprint)
蓝图使用起来就像应用当中的子应用一样,可以有自己的模板,静态目录,有自己的视图函数和URL规则,蓝图之间互相不影响.但是它们又属于应用中,可以共享应用的配置.对于大型应用来说,我们可以通过添加蓝图来扩 ...
- Flask蓝图的增删改查
怎样用flask蓝图来实现增删改查呢?请看下面的内容 这是我们的目录结构 从图中可以看出每一个功能都有一个各自的文件夹 首先我们要自己先来创建一个数据,在Flask_data.py中写入如下内容: S ...
- Flask蓝图基本使用
Flask蓝图基本使用 Flask通过使用蓝图将视图函数模块化,使应用显得更加规整 比如我们的应用的视图函数包括用户相关和文章相关,那么我们可以通过建立两个py文件分别存储两类视图函数 user.py ...
- Flask蓝图遇到的问题
欢迎加入python学习交流群 667279387 最近在使用flask开发一个业余学习项目,由于之前都是"小打小闹",整个程序都是放在一个文件夹里面的,也没有注意这个问题.这次项 ...
- Flask蓝图Blueprint和特殊装饰器
Flask 中的 蓝图 Blueprint 不能被run的flask实例:相当于django中的app01 应用 蓝图作用:功能隔离 路由隔离 Blueprint就是 一个不能run的flask 蓝图 ...
- Flask 蓝图进行路由分发.md
Flask 蓝图进行路由分发 Flask虽然说是一个轻型web框架,但也总不能用一个py文件写完全部view吧,所以我们要把路由分到不同的py文件中.这就需要用到蓝图了. 一 创建一个py文件 用于处 ...
- Flask 蓝图(Blueprint)使用方式解析
Flask蓝图提供了模块化管理程序路由的功能,使程序结构清晰.简单易懂.下面分析蓝图的使用方法 假如说我们要为某所学校的每个人建立一份档案,一个很自然的优化方式就是这些档案如果能分类管理,就是说假如分 ...
- 测试平台系列(4) 使用Flask蓝图(blueprint)
使用Flask蓝图(blueprint) 回顾 先来看一下上一篇的作业吧,使用「logbook」的时候,遇到了时区不对的情况.那么我们怎么去解决这个问题呢? 实际上logbook默认采用的是世界标准时 ...
随机推荐
- thinkphp5实现mysql数据库备份
其实备份数据库说白了就是向一个.sql的文档中写入一条一条的sql命令 public function back() { $to_file_name="backsql.sql"; ...
- 将RegEx(正则表达式提取器)与JMeter一起使用
JMeter的,最流行的开源性能测试工具,可以工作正则表达式,用正则表达式提取.正则表达式是一种用于通过使用高级操作提取文本的必需部分的工具.正则表达式在测试Web应用程序时很流行,因为它们可用于验证 ...
- Ubuntu同时忘记用户密码和root密码
在设置密码的时候,用到了小键盘,重启后再次用小键盘输入密码时,发现输入的并不是数字,而是其他符号.所以在设置关键信息的时候,小键盘还是得慎用啊. 解决方案: 在引导界面也就是开机倒计时的时候,按下 e ...
- 看完这篇文章,我奶奶都懂了https的原理
本文在个人技术博客同步发布,详情可猛戳 亦可扫描屏幕右方二维码关注个人公众号 Http存在的问题 上过网的朋友都知道,网络是非常不安全的.尤其是公共场所很多免费的wifi,或许只是攻击者的一个诱饵 ...
- JS正则改变字符之间文字
var reg = /([[^[]*])/g; html = html.replace(reg, "<span class=\"bold\">$1</s ...
- 将SpringBoot默认使用的tomcat替换为undertow
随着微服务的兴起,越来越多的互联网应用在选择web容器时使用更加轻量的undertow或者jetty.SpringBoot默认使用的容器是tomcat,如果想换成undertow容器,只需修改pom. ...
- @ConfigurationProperties
功能 将属性文件与一个Java类绑定,属性文件中的变量与Java类中的成员变量一一对应,无需完全一致. 如需将 @ConfigurationProperties 注解的目标类添加到Spring IOC ...
- linux 环境下备份oracle 数据库
登陆linux后,进入oracle的安装目录下,找到bin那个目录,进入bin目录ls -l 看这些命令的所有者: su - oracle这时会进入这个用户的主目录/home/oracle,此时,可以 ...
- Oracle listener.ora 设置
- 实现memcopy函数
实现memcopy函数: void * memcpy(void *dest, const void *src, unsigned int count); { if ((src == NULL) || ...