结构,如图:
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 Flaskdef create_app(): app = Flask(__name__) app.config.from_object('config') # 要返回回去 return app
此时在主文件中# -*- Coding: utf-8 -*-from app import create_appapp = create_app()if __name__ == '__main__': app.run(deBUG=app.config['DEBUG'])
二、用蓝图注册视图函数在蓝图中注册试图函数,在app/web/book.py
中,记得导入Blueprint# -*- Coding: utf-8 -*-from flask import Jsonify,Blueprintfrom helper import is_isbn_keyfrom 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 Flaskdef 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,Blueprintfrom helper import is_isbn_keyfrom 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 Blueprintweb = Blueprint ('web',__name__)# 这两个导入之后就可以成功的运行对应模块中相关的代码,注意这个位置,这蓝图实例化之后from app.web import bookfrom 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,requestfrom helper import is_isbn_keyfrom ShanqiuBook import ShanqiuBookfrom . 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,IntegerFIEldfrom wtforms.valIDators import Length,NumberRangeclass 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,requestfrom helper import is_isbn_keyfrom ShanqiuBook import ShanqiuBookfrom . 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 Flaskdef 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 appdef 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,String# 将模型映射到数据库中# 首先导入核心的对象from flask_sqlalchemy import sqlAlchemy# 初始化db = sqlAlchemy()# 继承db.Modelclass Book(db.Model): ID = Column(Integer,autoincrement=True) Title = Column(String(50),default='未名') binding = Column(String(20)) publisher = Column(String(50)) price = Column(String(20)) pages = Column(Integer) pubdate = Column(String(20)) isbn = Column(String(15),unique=True) summary = Column(String(1000)) image = Column(String(50))
在app/__init__.py
中进行模型与flask关联# -*- Coding: utf-8 -*-from flask import Flask# 导入这个dbfrom app.models.book import dbdef 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 appdef 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-蓝图、模型与CodeFirst所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)