数码与路由

By admin in 4858.com on 2019年4月13日

壹、应用、蓝图与视图函数

  1. 结构,如图:

    4858.com 1

  2. Flask最上层是app核心对象
    ,在这一个基本指标上得以插入很多蓝图,这么些蓝图是不能够独立存在的,必须将app作为插板插入app
    ,在每二个蓝图上,能够注册成百上千静态文件,视图函数,模板
    ,一个业务模块能够做为三个蓝图,比如book,以前的book.py
    放到了app/web/路径下,就是思量到了蓝图,app属于是全体Flask应用层,web属于是蓝图

  3. 一对起始化操作应该放入到__init__文件中,比如Flask的核心应用app初阶化对象,应该放入到在行使层级app包的
    __init__.py
    ,而蓝图的开首化应该放入到蓝图层的web包__init__.py中,如图:

    4858.com 2

  4. 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
  1. 此时在主文件中

# -*- coding: utf-8 -*-
from app import create_app

app = create_app()

if __name__ == '__main__':
    app.run(debug=app.config['DEBUG'])

数据

书本数据库的地址

# 基地址
http://t.yushu.im
# 关键字搜索
http://t.yushu.im/v2/book/search?q={}&start={}&count={}
# isbn搜索
http://t.yushu.im/v2/book/search/isbn/{isbn}
# 豆瓣api
https://api.douban.com/v2/book/1003078

使用Python的Flask框架营造大型Web应用程序的构造示例,pythonflask

尽管小型web应用程序用单个脚本能够很有益于,但那种格局却无法很好地扩展。随着应用变得复杂,在单个大的源文件中处理会变得难点重重。

与当先2/肆别的web框架差别,Flask对大型项目未有特定的团组织形式;应用程序的布局完全交由开发职员自个儿控制。在这一章,提出叁个大概的方法来公司管制二个巨型应用程序的包和模块。那种结构将用于书中其余的言传身教中。

1、项目组织

示例 基本多文件Flask应用结构

|-flasky
 |-app/
  |-templates/
  |-static/
  |-main/
   |-__init__.py
   |-errors.py
   |-forms.py
   |-views.py
  |-__init__.py
  |-email.py
  |-models.py
 |-migrations/
 |-tests/
  |-__init__.py
  |-test*.py
 |-venv/
 |-requirements.txt
 |-config.py
 |-manage.py

本条结构有四个顶层目录:

  • Flask应用一般放置在名叫app的目录下。
  • migrations目录包括数据库迁移脚本,那和此前说的一模1样。
  • 单元测试放置在test目录下
  • venv目录包括Python虚拟环境,那和事先说的也是同1的。

还有1对新的文件:

  • requirements.txt列出一些凭借包,那样就能够很不难的在不相同的微型总结机上配备2个均等的虚拟环境。
  • config.py存储了有个别布署安装。
  • manage.py用于运维应用程序和别的应用程序职责。

为了帮扶您一点一滴明了那几个结构,上边会讲述将hello.py应用改为契合这一布局的整个流程。

二、配置选项 应用程序常常供给多少个布局安装。最佳的例子正是在开发进度中供给运用差异的数据库,测试,生产环境,那样他们得以做到互不干扰。

我们得以行使配置类的层次结构来代表hello.py中的不难类字典结构布局。下边显示了config.py文件。

config.py:应用程序配置

import os
basedir = os.path.abspath(os.path.dirname(__file__))

class Config:
  SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard to guess string' 
  SQLALCHEMY_COMMIT_ON_TEARDOWN = True
  FLASKY_MAIL_SUBJECT_PREFIX = '[Flasky]'
  FLASKY_MAIL_SENDER = 'Flasky Admin <[email protected]>' 
  FLASKY_ADMIN = os.environ.get('FLASKY_ADMIN')

  @staticmethod
  def init_app(app): 
    pass

class DevelopmentConfig(Config): 
  DEBUG = True

  MAIL_SERVER = 'smtp.googlemail.com'
  MAIL_PORT = 587
  MAIL_USE_TLS = True
  MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
  MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD') 
  SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or \
    'sqlite:///' + os.path.join(basedir, 'data-dev.sqlite')

class TestingConfig(Config): 
  TESTING = True
  SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_URL') or \
    'sqlite:///' + os.path.join(basedir, 'data-test.sqlite')

class ProductionConfig(Config):
  SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
    'sqlite:///' + os.path.join(basedir, 'data.sqlite')

config = {
  'development': DevelopmentConfig,
  'testing': TestingConfig,
  'production': ProductionConfig,
  'default': DevelopmentConfig
}

Config基类包蕴部分均等配置;差异的子类定义不相同的布局。额外安顿能够在急需的时候在加盟。

为了让配置更加灵敏更安全,壹些设置能够从环境变量中程导弹入。例如,SECRET_KEY,由于它的敏感性,可以在环境中装置,但倘若条件中并未有概念就不能够不提供2个暗许值。

在多个布局中SQLALCHEMY_DATABASE_ULANDI变量能够分配分化的值。那样应用程序能够在分歧的安排下运营,各样能够选取分歧的数据库。

配备类能够定义三个将应用程序实例作为参数的init_app()静态方法。那里一定于配置的开端化是可以执行的。那里Config基类实现贰个空init_app()方法。

在布署脚本的最底层,那么些不相同的布局是注册在布局字典中。将在这之中一个布置(开发配置)注册为默许配置。

三、应用程序包 应用程序包放置了独具应用程序代码、模板和静态文件。它被略去的名字为app,也能够给定八个一定于接纳的名目(假如需求的话)。templates和static目录是应用的1有些,因而这五个目录应当放置在app中。数据库模型和电子邮件帮助成效也要置入到那个包中,每个都以app/models.py和app/email.py情势存入自身的模块个中。

3.①、使用二个应用程序工厂

在单个文件中创立应用程序的主意特别有益,可是它有3个大缺点。因为应用程序成立在大局范围,未有艺术动态的适应应用配置的改变:脚本运维时,应用程序实例已经创立,所以它曾经来比不上更改配置。对于单元测试那是专程首要性的,因为有时候须求在不一致的配置下运作应用程序来取得越来越好的测试覆盖率。

杀鸡取蛋那壹题材的秘诀正是将应用程序放入三个工厂函数中来拖延创制,那样就足以从剧本中显式的调用。

那不光给脚本丰硕的时刻来安装配置,也能用来创立四个应用程序实例——一些在测试进程中国和欧洲常实惠的事物。被定义在app包的构造函数中的应用程序工厂函数会在演示7-3中显得。

那一个构造函数导入超过2/4当下急需利用的扩充,但因为尚未应用程序实例开头化它们,它能够被创设但不初叶化通过不传递参数给它们的构造函数。create_app()即应用程序工厂函数,须求传入用于应用程序的布署名。配置中的设置被保存在config.py中的三个类中,能够利用Flask的app.config配置对象的from_object()方法来直接导入。配置对象足以因此对象名从config字典中选出。一旦应用程序被成立且布局好,扩大就可以被初叶化。调用扩充里的init_app()从前先创建并成功开头化学工业作。

app/ _init__.py:应用程序包构造函数_

from flask import Flask, render_template 
from flask.ext.bootstrap import Bootstrap 
from flask.ext.mail import Mail
from flask.ext.moment import Moment
from flask.ext.sqlalchemy import SQLAlchemy 
from config import config

bootstrap = Bootstrap()
mail = Mail()
moment = Moment()
db = SQLAlchemy()

def create_app(config_name):
  app = Flask(__name__) 
  app.config.from_object(config[config_name]) 
  config[config_name].init_app(app)

  bootstrap.init_app(app)
  mail.init_app(app)
  moment.init_app(app)
  db.init_app(app)

  # attach routes and custom error pages here

  return app

工厂函数重回创造的应用程序实例,可是请留意,在当下情状下使用工厂函数创设的应用程序是不完整的,因为它们并未有路由和自定义错误页面处理程序。那是下一节的核心。

叁.贰、在蓝图中落成应用程序的成效

应用程序工厂的转会工作引出了路由的复杂化。在单脚本应用中,应用程序实例是大局的,所以可以很简单地采用app.route装饰器定义路由。不过今后应用程序在运维时成立,app.route装饰器唯有在create_app()调用后才开头存在,那就太迟了。就像是路由那样,那一个经过app.errorhandler装饰器定义的自定义错误页面处理程序也存在同样的题材。

幸运的是Flask使用蓝图来提供3个越来越好的解决方案。3个蓝图就就像于3个能够定义路由的应用程序。差异的是,和路由相关联的蓝图都在蛰伏状态,只有当蓝图在利用中被登记后,此时的路由才会化为它的一部分。使用定义在全局意义域下的蓝图,定义应用程序的路由就少了一些能够和单脚本应用程序1样简单了。

和应用程序一样,蓝图能够定义在贰个文本或2个包中与七个模块一起开创更结构化的法子。为了追求最大的油滑,可以在应用程序包中成立子包来具有蓝图。上面体现了创建蓝图的构造函数。

app/main/ _init__.py:成立蓝图_

from flask import Blueprint

main = Blueprint('main', __name__) 

from . import views, errors

蓝图是经超过实际例化Blueprint类对象来创设的。那个类的构造函数接收八个参数:蓝图名和蓝图所在的模块或包的职位。与应用程序一样,在抢先53%状态下,对于第二个参数值使用Python的__name__变量是正确的。

应用程序的路由都保存在app/main/views.py模块内部,而错误处理程序则保存在app/main/errors.py中。导入那些模块可以使路由、错误处理与蓝图相关联。首要的是要注意,在app/init.py脚本的最底层导入模块要幸免循环重视,因为view.py和errors.py都需求导入main蓝图。

蓝图和应用程序一样注册在create_app()工厂函数中,如下所示。

示例 app/ _init__.py:蓝图注册_

def create_app(config_name): 
  # ...
  from .main import main as main_blueprint 
  app.register_blueprint(main_blueprint)

  return app

上面则展现了错误处理。

app/main/errors.py:蓝图的错误处理

from flask import render_template 
from . import main

@main.app_errorhandler(404) 
def page_not_found(e):
  return render_template('404.html'), 404

@main.app_errorhandler(500) 
def internal_server_error(e):
  return render_template('500.html'), 500

在蓝图中写错误处理的差别之处是,若是利用了errorhandler装饰器,则只会调用在蓝图中滋生的错误处理。而应用程序范围内的错误处理则必须运用app_errorhandler。

这边显得了被更新在蓝图中的应用程序路由。

app/main/views.py:带有蓝图的应用程序路由

from datetime import datetime
from flask import render_template, session, redirect, url_for

from . import main
from .forms import NameForm 
from .. import db
from ..models import User

@main.route('/', methods=['GET', 'POST']) 
def index():
  form = NameForm()
  if form.validate_on_submit():
    # ...
    return redirect(url_for('.index')) 
  return render_template('index.html',
              form=form, name=session.get('name'),
              known=session.get('known', False),
              current_time=datetime.utcnow())

在蓝图中写视图函数有两大分歧点。第2,正如前边的错误处理壹样,路由装饰器来自于蓝图。第三个不等是url_for()函数的应用。你大概会纪念,该函数的率先个参数为路由节点名,它给基于应用程序的路由内定私下认可视图函数。例如,单脚本应用程序中的index()视图函数的U福睿斯L能够经过url_for(‘index’)来获得。

不一样的是Flask名称空间适用于来自蓝图的持有节点,那样八个蓝图能够运用同一节点定义视图函数而不会发出争辩。名称空间正是蓝图名(Blueprint构造函数中的第一个参数),所以index()视图函数注册为main.index且它的ULX570L能够由此url_for(‘main.index’)获得。

在蓝图中,url_for()函数同样支撑越来越短格式的节点,省略蓝图名,例如url_for(‘.index’)。有了那么些,就能够这么使用当前恳请的蓝图了。那其实意味着相同蓝图内的重定向能够运用更加短的花样,假若重定向跨蓝图则必须运用带名称空间的节点名。

做到了应用程序页面更改,表单对象也保存在app/main/forms.py模块中的蓝图里面。

四、运转脚本 顶层目录中的manage.py文件用于运营应用。

manage.py:运行脚本

#!/usr/bin/env python
import os
from app import create_app, db
from app.models import User, Role
from flask.ext.script import Manager, Shell
from flask.ext.migrate import Migrate, MigrateCommand

app = create_app(os.getenv('FLASK_CONFIG') or 'default') 
manager = Manager(app)
migrate = Migrate(app, db)

def make_shell_context():
  return dict(app=app, db=db, User=User, Role=Role)

manager.add_command("shell", Shell(make_context=make_shell_context))
manager.add_command('db', MigrateCommand)

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

其一本子开头于创立应用程序。使用环境变量FLASK_CONFIG,若它早已定义了则从中获得配置;借使未有,则是用暗中认可配置。然后用于Python
shell的Flask-Script、Flask-Migrate以及自定义上下文仲被初步化。

为了便利,会增多一行执行环境,这样在基于Unix的操作系统上得以通过./manage.py来执行脚本来替代冗长的python
manage.py。

伍、供给文件 应用程序必须含有requirements.txt文件来记录全体依赖包,包涵精确的版本号。那很首要,因为能够在不一致的机器上海重机厂新生成虚拟环境,例如在生养条件的机器上配备应用程序。这些文件能够经过上面包车型大巴pip命令自动生成:

(venv) $ pip freeze >requirements.txt

数码与路由。当安装或更新一个包事后最佳再立异一下这一个文件。以下呈现了八个急需文件示例:

Flask==0.10.1
Flask-Bootstrap==3.0.3.1
Flask-Mail==0.9.0
Flask-Migrate==1.1.0
Flask-Moment==0.2.0
Flask-SQLAlchemy==1.0
Flask-Script==0.6.6
Flask-WTF==0.9.4
Jinja2==2.7.1
Mako==0.9.1
MarkupSafe==0.18
SQLAlchemy==0.8.4
WTForms==1.0.5
Werkzeug==0.9.4
alembic==0.6.2
blinker==1.3
itsdangerous==0.23

当你需求完善复制八个虚拟环境的时候,你能够运作以下命令创造八个新的虚拟环境:

(venv) $ pip install -r requirements.txt

当您读到这时,示例requirements.txt文件中的版本号或然已经过时了。即使喜欢您能够品味用方今公告的包。假若遇上别的难题,你能够每1天回退到供给文件中与运用兼容的钦定版本。

陆、单元测试 其一动用不大以至于不必要太多的测试,可是作为示例会在演示中彰显七个简易的测试定义。

示例:tests/test_basics.py:单元测试

import unittest
from flask import current_app 
from app import create_app, db

class BasicsTestCase(unittest.TestCase): 
  def setUp(self):
    self.app = create_app('testing')
    self.app_context = self.app.app_context()
    self.app_context.push()
    db.create_all()

  def tearDown(self): 
    db.session.remove() 
    db.drop_all() 
    self.app_context.pop()

  def test_app_exists(self): 
    self.assertFalse(current_app is None)

  def test_app_is_testing(self): 
    self.assertTrue(current_app.config['TESTING'])

编纂好的测试使用的是发源于Python标准库中规范的unittest包。setUp()和tearDown()方法在每一种测试以前和后来运转,且任何贰个方法必须以test_开班作为测试来执行。

建议:假若您想要学习更加多使用Python的unittest包来写单元测试的剧情,请参阅官方文书档案。
setUp()方法尝试成立1个测试环境,类似于运作应用程序。首先它创立应用程序配置用于测试并激活上下文。这一步确定保障测试能够和正规请求一样访问current_app。然后,当须要的时候,能够创造二个供测试使用的全新数据库。数据库和应用程序上下文少禽在tearDown()方法中被移除。

先是个测试确定保障应用程序实例存在。第三个测试确认保证应用程序在测试配置下运作。为了保险tests目录有效,供给在tests目录下扩充__init__.py文件,可是该文件可以为空,这样unittest包能够扫描全体模块并固定测试。

建议:即使您有克隆在GitHub上的应用程序,你以后能够运营git checkout
七a来切换成那个本子的应用程序。为了保险您早已安装了颇具正视集,须要周转pip
install -r requirements.txt。
为了运维单元测试,能够在manage.py脚本中扩大贰个自定义的下令。

下边呈现怎样添加测试命令。

以身作则:manage.pyt:单元测试运维脚本

@manager.command
def test():
  """Run the unit tests."""
  import unittest
  tests = unittest.TestLoader().discover('tests') 
  unittest.TextTestRunner(verbosity=2).run(tests)

manager.command装饰器使得它能够很简单的落到实处自定义命令。棉被服装饰的函数名能够被看做命令名使用,且函数的文书档案字符串会呈现帮助新闻。test()函数的推行会调用unittest包中的测试运营器。

单元测试能够像下边那样实践:

(venv) $ python manage.py test

test_app_exists (test_basics.BasicsTestCase) ... ok
test_app_is_testing (test_basics.BasicsTestCase) ... ok

.----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK

七、数据库运转 与单脚本的行使比较,重构后的采纳使用差异数据库。

4858.com,从环境变量中得到的数据库U酷威L作为首选,默许SQLite数据库作为可选。三个布局中的环境变量和SQLite数据库文件名是不雷同的。例如,开发配置的U途睿欧L是从DEV_DATABASE_U宝马X三L环境变量中拿走,如若未有定义则会采纳名叫data-dev.sqlite的SQLite数据库。

甭管数据库URAV四L源的是哪多个,都无法不为新的数据库创造数量库表。假若利用了Flask-Migrate来维系迁移跟踪,数据库表可以被创建或更新到近日的版本通过上面包车型大巴通令:

(venv) $ python manage.py db upgrade

相信与否,已经到了第贰有的了结的地点。你未来早就学到了Flask须求的基本要素,可是你不明确什么将这一个零碎的学问结合在1块儿形成三个真正的应用程序。第二有个其他目标是透过支付二个总体的应用程序来指导你继续上扬。

即便小型web应用程序用单个脚本能够很便利,但那种艺术却不可能很好地扩张…

flask是python的3个web应用框架,django很多少人听过,flask相比少见,连创办者1先河写出来只是个笑话而已,对python三支撑不太好,flask的利益是微应用,有需要的插件才使用,精简而灵活,由于灵活,要怎么开创贰个体系要协调去想想怎么搭建,不像django帮你做完项目搭建的手续。个人觉得怎么搭建三个门类也是三个就学后台架构的历程。那里不会详细介绍flask和flask各类模块的法力,留作思虑与上学。

2、用蓝图注册视图函数

  1. 在蓝图中注册试图函数,在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)
  1. 在蓝图中注册了准备函数,还亟需把蓝图插入到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)

搜寻关键字

  1. 基于上边的地方能够驾驭搜索的时候有三种格局,而对此isbn搜索,又分为二种isbn13 由13个0-9在数字组成,isbn10 由10表0-9表数字组组成,中间可能包含' - ' ,于是要分开来判定
  2. 在函数中要小心:isdigit()能够看清是不是为数字
    replace()用来替换,

@app.route("/search/<q>/<page>")
def search(q,page):
    """
    搜索书籍路由
    :param q: 关键字 OR isbn
    :param page: 页码
    """
    isbn_or_key = 'key'
    # 1. 判断长度是否为13且是否为数字
    if len(q) == 13 and q.isdigit():
        isbn_or_key = 'isbn'
    # 2. 把-替换掉,判断是否为纯数字
    short_q = q.replace('-', '')
    if '-' in q and len(short_q) == 10 and short_q.isdigit():
        isbn_or_key = 'isbn'
    pass
  1. 多逻辑判断的时候,应该把结果望着为假的内置后边,对数据库操作的内置后边,那样方便节约财富
|-flasky
  |-apps/
    |-templates/
    |-static/
    |-main/
      |-__init__.py
      |-errors.py
      |-forms.py
      |-views.py
    |-__init__.py
    |-email.py
    |-models.py
  |-migrations/
  |-tests/
    |-__init__.py
    |-test*.py
  |-venv/
  |-requirements.txt
  |-config.py
  |-manage.py
  |-command.py

3、单蓝图多模块拆分视图函数

  1. 蓝图,正是为着分模块的,比如三个web系统正是属于叁个web模块,二个运动端选择的api正是一个api模块,而大家那里的book,user等不等类其余py文件,假若每2个都登记一个蓝图的话就有点司空眼惯了,所以要实行单蓝图
  2. 在一个模块(web)的开始文件中定义蓝图对象,然后那个模块中的其余的py文件引用的正是那贰个蓝图对象来注册路由函数,
  3. 在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)
  1. 此间先创建3个伪代码user.py,为了多3个模块实行出现说法

# -*- coding: utf-8 -*-
# 导入web模块
from . import web
@web.route("/user/login")
def login():
    return "success"
  1. 此时在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

一言以蔽之的重构

  1. 上边包车型大巴代码都写到视图中如此不妥,展现不了封装性,看起来不佳,应该把2个完成的意义封装起来,建立贰个函数,方便日后的管住
  2. 在目录下树立1个helper.py文本,这些文件器重正是提供部分方法,把上面的内容放到那里,只供给回到贰个值就能够了

# -*- coding: utf-8 -*-

def is_isbn_or_key(word):
    isbn_or_key = 'key'
    if len(word) == 13 and word.isdigit():
        isbn_or_key = 'isbn'

    short_word = word.replace('-', '')
    if '-' in word and len(short_word) == 10 and short_word.isdigit():
        isbn_or_key = 'isbn'

    return isbn_or_key
  1. 在主文件中调用那些法子就足以了,记得传值,和收取再次回到的值

# -*- coding: utf-8 -*-

from flask import Flask,make_response
# 1. 这里要导入
from helper import is_isbn_or_key

app = Flask(__name__)
app.config.from_object('config')

@app.route('/book/search/<q>/<page>')
def search(q,page):
    # 2. 调用方法即可
    is_or_key = is_isbn_or_key(q)
    pass

if __name__ == '__main__':
    app.rundebug=app.config['DEBUG'])

品类有三个顶层目录:

四、Request对象

  1. 在app/web/book.py文件中,定义的url请求是/book/search/<q>/<page>那种格式的,Flask会将<>里的值自动映射成视图函数方法的参数,可是那种格式用着不爽,要把用户输入的参数作为请求参数字传送入,那年就要选用那种格式了http://127.0.0.1:5000/book/search/?q=金庸&page=1
  2. 这么些该怎么获取值呢,今年就用到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)
  1. Flask的request是依照代理情势达成的,想让request正常使用,必须确认保证是http请求触发的函数或视图函数中利用

requests请求

  1. 因为那几个连串要拜访分歧的网站,所以在目录下新建3个http.py文件,专门用来提供访问网站
  2. 此处运用的requests,要先举行设置,注意:代码写的时候势供给精简,相对不要接纳python的首要字,防止与Python的模块抵触并导致此错误,把那些类名http改为其他名称

# -*- coding: utf-8 -*-

import requests
class aaa:

    # 传入url和是否返回的是json数据,这里是静态方法
    @staticmethod
    def get(url,return_json=True):
        # 发送get请求
        r = requests.get(url)
        # 因为有的url返回的json数据,但是有的并不是,所以加一个判断,不是的话返回文本
        # 还要判断状态码,200的话就是访问成功有数据
        if r.status_code != 200:
            return {} if return_json else ''
        return r.json() if return_json else r.text

        # 下面的写法太low
        # if r.status_code == 200:
        #     if return_json:
        #         return r.json()
        #     else:
        #         return r.text
        # else:
        #     if return_json:
        #         return {}
        #     else:
        #         return ''
  • app的目录下是放Flask应用
  • migrations目录包涵数据库迁移脚本
  • test目录下是放单元测试
  • venv是Python虚拟环境
  • requirements.txt是Python运营的借助包列表
  • config.py是铺排安装脚本
  • manage.py 用于运营应用程序和其他应用程序职务
  • command.py 控制

5、WTForms参数验证

  1. 上边我们把url改了,不过只要用户输入了一些非正规的记号该如何做?那个时候就要选拔到参数验证,而WTForms框架正是贰个可观的参数验证框架,首先在相应的条件中开始展览设置(flask--yQglGu4) E:\py\qiyue\flask>pipenv install wtforms
  2. 其壹参数验证写在何地好吧,直接写在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)
  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':'参数校验失败'})

从API中获取数据

  1. 首先在目录下定义贰个类,用于用于获取数据,ShanqiuBook,

# -*- coding: utf-8 -*-

from http import aaa
class ShanqiuBook:

    isbn_url = 'http://t.yushu.im/v2/book/search/isbn/{}'
    keyword_url = 'http://t.yushu.im/v2/book/search?q={}&count={}&start={}'


    # 根据isbn进行搜索,这里使用这个静态装饰器,调用类变量更加的方便
    @classmethod
    def search_by_isbn(cls,isbn):
        # 调用类变量,
        url = cls.isbn_url.format(isbn)
        # 调用上面的方法用于请求网址
        result = aaa.get(url)
        # 这里返回的是json数据,但是在py中就是字典了
        return result

    # 根据关键字进行搜索
    @classmethod
    def search_by_keyword(cls,keyword,count=15,start=0):
        url = cls.keyword_url.format(keyword,count,start)
        result = aaa.get(url)
        return result
  1. 接下来在视图中得到重回的数码

# -*- coding: utf-8 -*-

from flask import Flask
from helper import is_isbn_or_key

from flask import jsonify
# 实例化
from shanqiu_book import ShanQiuBook

app = Flask(__name__)
# 载入这个配置文件
app.config.from_object('config')

@app.route('/book/search/<q>/<page>')
def search(q,page):
     is_or_key = is_isbn_or_key(q)
     if is_or_key == 'isbn':
         # 这里直接使用使用类名调用就可以
         result = ShanQiuBook.search_by_isbn(q)
    else:
         result = ShanQiuBook.search_by_keyword(q)

    # 因为返回的是json数据,要手动的进行解析,这样写的话非常麻烦
    # return json.dumps(result), 200, {'content-type': 'application/json'}
    # 这里使用flask自带的jsonify替换麻烦的json.dumps和元组
     return jsonify(result)


if __name__ == '__main__':
    app.run(debug=app.config['DEBUG'])

app层

app上面有main、static、templates八个文本夹以及init.py、email.py、models.py

  • main文本夹用来保存蓝本,此文件夹下
    init.py文件之中创制蓝本,(蓝本和程序类似,也足以定义路由。分裂的是,在原本中定义的路由处于休眠状态,直到蓝本注册到程序上后,路由才真的变成程序的一片段。)main文件夹下views.py用来保存程序的路由,errors.py用来处理错误,forms.py是存放表单定义。

    • init.py

      和路由相关联的蓝图都在蛰伏状态,惟有当蓝图在选择中被注册后,此时的路由才会化为它的一有的。使用定义在大局意义域下的蓝图,定义应用程序的路由就差不离可以和单脚本应用程序1样简单了。

      蓝图能够定义在多个文书或1个包中与多个模块壹起开创更结构化的章程。为了追求最大的油滑,能够在应用程序包中创造子包来全数蓝图。

      # app/main/ _init__.py:创建蓝图_
      from flask import Blueprint
      main = Blueprint('main', __name__) 
      from . import views, errors
      

      蓝图是经超过实际例化Blueprint类对象来创建的。那么些类的构造函数接收多少个参数:蓝图名和蓝图所在的模块或包的任务。与应用程序1样,在大部气象下,对于第一个参数值使用Python的__name__变量。

      应用程序的路由都保存在app/main/views.py模块内部,而错误处理程序则保存在app/main/errors.py中。导入这几个模块可以使路由、错误处理与蓝图相关联。主要的是要专注,在app/init.py本子的平底导入模块要制止循环信赖,因为view.pyerrors.py都急需导入main蓝图。

      # app/ _init__.py:蓝图注册_
      def create_app(config_name): 
      
          from .main import main as main_blueprint 
          app.register_blueprint(main_blueprint)
      
          return app
      
    • errors.py

      在蓝图中写错误处理的差别之处是,假使利用了errorhandler装饰器,则只会调用在蓝图中滋生的错误处理。而应用程序范围内的错误处理则必须利用app_errorhandler

      # app/main/errors.py:蓝图的错误处理
      from flask import render_template 
      from . import main
      
      @main.app_errorhandler(404) 
      def page_not_found(e):
          return render_template('404.html'), 404
      
      @main.app_errorhandler(500) 
      def internal_server_error(e):
          return render_template('500.html'), 500
      
    • views.py

      # app/main/views.py:带有蓝图的应用程序路由
      from datetime import datetime
      from flask import render_template, session, redirect, url_for
      
      from . import main
      from .forms import NameForm 
      from ..models import User
      
      @main.route('/',methods = ['POST','GET'])   #请求方式不管是post还是get都执行这个视图函数
      def index():
          form = NameForm()  #表单实例
          if form.validate_on_submit():   #提交按钮是否成功点击
               # 从数据库中查找和表单数据一样的数据,如果有,取第一个数据
              user = User.query.filter_by(username = form.name.data).first()
              if user is None:   #如果数据库中没有对应的数据
                  user = User(username = form.name.data)  #在数据库中对应的表中创建数据
                  db.session.add(user)  #加入到用户会话,以便数据库进行提交
                  session['known'] = False  #这是一个新用户
                  if current_app.config['FLASKY_ADMIN']:  #如果收件人已经定义,则调用发送邮件函数
                      send_email(current_app.config['FLASKY_ADMIN'],'New User','mail/new_user',user = user)
                      flash('The mail has been sent out')
              else:
                  session['known'] = True  #这是一个老用户
              session['name'] = form.name.data   #从表单获取数据
              return redirect(url_for('.index'))
          return render_template('index.html',current_time = datetime.utcnow(),
                                 form = form,name=session.get('name'),known
      

在蓝图中写视图函数有两大不一样点。第二,正如以前的错误处理壹样,路由装饰器来自于蓝图。第1个例外是url_for()函数的应用。该函数的率先个参数为路由节点名,它给基于应用程序的路由钦赐暗中同意视图函数。例如,单脚本应用程序中的index()视图函数的U福特ExplorerL能够经过url_for(‘index’)来获得。

Flask名称空间适用于来自蓝图的具备节点,那样四个蓝图能够选拔同样节点定义视图函数而不会爆发争辨。名称空间便是蓝图名(Blueprint构造函数中的首个参数),所以index()视图函数注册为main.index且它的U大切诺基L能够透过url_for(main.index)获得。

rl_for()函数同样协理更加短格式的节点,省略蓝图名,例如url_for(‘.index’)。有了那么些,就足以如此使用当前呼吁的蓝图了。那实则意味着相同蓝图内的重定向可以应用越来越短的样式,借使重定向跨蓝图则必须使用带名称空间的节点名。

完结了应用程序页面更改,表单对象也保存在app/main/forms.py模块中的蓝图里面。

  • static**存放静态文件

  • templates用来存放响应的html文件,mail子文件之中的用于保存发送邮件所需的.html和.txt文件

  • init.py文件之中含有create_app()函数,已经app的种种开首化。

    在单个文件中开创应用程序的章程越发便于,然则它有三个大胜笔。因为应用程序创设在大局范围,未有艺术动态的适应应用配置的改动:脚本运行时,应用程序实例已经创立,所以它曾经来不比更改配置。化解这一难点的方法就是将应用程序放入三个工厂函数中来推迟创造,那样就足以从剧本中显式的调用。那不只给脚本充分的岁月来设置配置,也能用来创建多少个应用程序实例。

    那么些构造函数导入大部分当下急需接纳的扩大,但因为从没应用程序实例伊始化它们,它能够被创立但不开头化通过不传递参数给它们的构造函数。create_app()即应用程序工厂函数,供给传入用于应用程序的安排行。配置中的设置被保存在config.py中的一个类中,能够动用Flask的app.config配备对象的from_object()方法来平素导入。配置对象足以因此对象名从config字典中选出。一旦应用程序被创设且布局好,扩大就足以被发轫化。调用扩大里的init_app()事先先创建并形成开头化学工业作。

    # app/ _init__.py:应用程序包构造函数
    from flask import Flask, render_template 
    from flask.ext.bootstrap import Bootstrap 
    from flask.ext.mail import Mail
    from flask.ext.moment import Moment
    from flask.ext.sqlalchemy import SQLAlchemy 
    from config import config
    
    bootstrap = Bootstrap()
    mail = Mail()
    moment = Moment()
    db = SQLAlchemy()
    
    def create_app(config_name):
        app = Flask(__name__) 
        app.config.from_object(config[config_name]) 
        config[config_name].init_app(app)
    
        bootstrap.init_app(app)
        mail.init_app(app)
        moment.init_app(app)
        db.init_app(app)
    
        return app
    

  • email.py包含send_email()发送文书函数(异步)

  • models.py富含User和Role七个表定义

陆、拆分配置文件

  1. 前边访问数据的时候,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)
  1. 如此写卓殊的不妥

    • 在视图函数中收受到的参数是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的一个钱打二15个结是多少个独自的逻辑,应该用封装成贰个措施,使用的时候一向调用

      # 获取每一页的起始下标
          @staticmethod
          def calculate_start(page):
              # 获取配置信息中的每页显示的数量
              return (page -1 ) * current_app.config['PER_PAGE']
      
  2. 重构后的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']​
  1. 本条时候在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)

将视图函数拆分到单独的文件中

  1. 倘使视图函数都写在主文件中,不便利爱戴,而是应该把他们放入到四个文本中,每3个模块正是一个精算,用的时候平昔引用,那样方便保险
  2. 在根目录下树立多少个app/web文件夹,在这一个文件夹上面建立三个book.py文件,专门用来存放在book模块,然后在主文件中援引这么些模块就能够了,book.py

# -*- coding: utf-8 -*-
from flask import jsonify
from helper import is_isbn_key
from ShanqiuBook import ShanqiuBook

# 为了让book.py模块可以使用app对象
from demo import app

@app.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)
  1. 那儿的主文件中

# -*- coding: utf-8 -*-
from flask import Flask
# 为了可以注册book.py中的路由
from app.web import book

app = Flask(__name__)
app.config.from_object('config')

if __name__ == '__main__':
    app.run(debug=app.config['DEBUG'])
  1. 唯独这么写的话,会油可是生40四,因为出现了循环引用

config.py 应用配置示范

config.py中包涵3个基类Config定义,八个继续类定义DevlopmentConfig、TestingConfig、ProductionConfig和一个字典config

import os
basedir = os.path.abspath(os.path.dirname(__file__))

class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard to guess string' 
    SQLALCHEMY_COMMIT_ON_TEARDOWN = True
    FLASKY_MAIL_SUBJECT_PREFIX = '[Flasky]'
    FLASKY_MAIL_SENDER = 'Flasky Admin <flasky@example.com>' 
    FLASKY_ADMIN = os.environ.get('FLASKY_ADMIN')

    @staticmethod
    def init_app(app): 
        pass

class DevelopmentConfig(Config): 
    DEBUG = True

    MAIL_SERVER = 'smtp.googlemail.com'
    MAIL_PORT = 587
    MAIL_USE_TLS = True
    MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
    MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD') 
    SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or \
        'sqlite:///' + os.path.join(basedir, 'data-dev.sqlite')

class TestingConfig(Config): 
    TESTING = True
    SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_URL') or \
        'sqlite:///' + os.path.join(basedir, 'data-test.sqlite')

class ProductionConfig(Config):
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
        'sqlite:///' + os.path.join(basedir, 'data.sqlite')

config = {
    'development': DevelopmentConfig,
    'testing': TestingConfig,
    'production': ProductionConfig,
    'default': DevelopmentConfig
}

Config基类包涵部分1如既往配置;区别的子类定义区别的铺排。额外安排可以在需求的时候在参预。

为了让配置更加灵敏更安全,1些装置能够从环境变量中程导弹入。例如,SECRET_KEY,由于它的敏感性,可以在环境中设置,但倘诺条件中平素不概念就亟须提供叁个暗中同意值。

在多少个布局中SQLALCHEMY_DATABASE_URI变量能够分配不相同的值。那样应用程序能够在区别的配置下运作,每一种能够动用分歧的数据库。

计划类可以定义八个将应用程序实例作为参数的init_app()静态方法。那里一定于配置的伊始化是可以进行的。那里Config基类完成1个空init_app()方法。

在布署脚本的底层,那么些不一致的配置是注册在配备字典中(config)。将里面3个安插(开发配置)注册为私下认可配置。

7、定义第二个模型类

  1. 咱俩今日把文件进行整理,如下:

4858.com 3

  1. 第3在地点创造3个数据库,如下:

4858.com 4

  1. 在app/models/book.py文件中树立模型,这里运用到sqlalchemy来兑现自动化映射,在Flask框架中对那些进行了改良Flask_SQLAlchemy,那么些更是人性化,安装(flask--yQglGu4) E:\py\qiyue\flask>pipenv install flask-sqlalchemy

  2. 建模,那样就确立好了模型

# -*- 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

巡回引进流程分析

  1. 因为在全方位的流程中,app四次起先化,如图
  2. 4858.com 5
  3. 总体工艺流程中,出现了一回宗旨app对象的初步化,注册路由是在白灰流程中开始化的app注册的。可是运维服务是新民主主义革命流程中的app运营的
  4. book中注册路由所采纳的app对象,是她协调所导入fisher模块的app对象(莲灰流程中),而不是乙巳革命主流程中所实例化的app对象
  5. 标题一:因为都是由fisher引进book,二个模块只会引进另三个模块一回,所以只举办了贰遍book
  6. 题材二:由于三次是主流程执行fisher文件;二回是由book模块导入 fisher
  7. 为了表明大家的定论,大家在app实例化,运维,注册路由是哪个地点进入日志新闻,

print("id为"+str(id(app))+"的app注册路由")
@app.route("/book/search/<q>/<page>")
def search(q, page):
    isbn_or_key = is_isbn_or_key(q)
    if isbn_or_key == 'isbn':
        result = YuShuBook.search_by_isbn(q)
    else:
        result = YuShuBook.search_by_key(q)
    return jsonify(result)
  1. 主文件

app = Flask(__name__)
print("id为"+str(id(app))+"的app实例化")
app.config.from_object("config")
# 为了可以注册book.py中的路由
from app.web import book
if __name__ == '__main__':
    print("id为" + str(id(app)) + "的app启动")
    app.run(debug=app.config['DEBUG'])
  1. 结果如下

id为92323280的app实例化
id为107142192的app实例化
id为107142192的app注册路由
id为92323280的app启动

能够看到注册路由的app,和起步服务的app不是同一个app。并且最后运行的app是首先实例化的app,也正是辛酉革命主流程的app;而注册路由的app是后实例化的app,也便是由book导入fisher模块的深灰蓝流程的app

manage.py

包含app创建,manage、migrate初始化,以及make_shell_context()函数在命令行获取上下文,制止频繁导入还有test()函数,用来测试。

# manage.py
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand

from wsgi import app
from models.base import db

migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command("db", MigrateCommand)

if __name__ == "__main__":
    manager.run()

捌、将模型映射到数据库中

  1. 在模型类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))
  1. 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)
  1. 布局数据库连接的布局文件在app/secure.py文件中

# -*- coding: utf-8 -*-

# 存放比较机密的配置文件
DEBUG = True

# 数据库连接url,固定格式
# 要连接的数据库类型,数据库驱动(这里还要进行安装:pipenv install cymysql)
SQLALCHEMY_DATABASE_URI = 'mysql+cymysql://root:123456@localhost:3306/book'
  1. 随后运营品种,就会创立在内定的数据库中开创八个数据表了,然则运营品种会出现上面包车型客车那种张冠李戴

    'No application found. Either work inside a view function or push'

这个是因为在Flask中,不是实例化了app核心对象,其他代码就可以直接使用,要在上面的第二步的注意事项中` db.create_all()`方法中,把app核心对象传入即可

db.create_all(app=app),那样就足以了,在数据库中就能够看来表了

4858.com 6

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有