数量与路由

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

  1. 结构,如图:

    亚洲必赢手机入口 1

  2. Flask最上层是app核心对象
    ,在那在这之中央目的上能够插入很多蓝图,这么些蓝图是无法独立存在的,必须将app作为插板插入app
    ,在每贰个蓝图上,能够登记成都百货上千静态文件,视图函数,模板
    ,二个事情模块能够做为3个蓝图,比如book,在此以前的book.py
    放到了app/web/路径下,正是记挂到了蓝图,app属于是全数Flask应用层,web属于是蓝图

  3. 壹些开端化操作应该放入到__init__文本中,比如Flask的中坚应用app初阶化对象,应该放入到在运用层级app包的
    __init__.py
    ,而蓝图的开头化应该放入到蓝图层的web包__init__.py中,如图:

    亚洲必赢手机入口 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应用程序用单个脚本能够很有利,但那种办法却不能够很好地扩大。随着应用变得复杂,在单个大的源文件中拍卖会变得难点重重。

与大部分任何web框架不相同,Flask对大型项目未有特定的团组织办法;应用程序的构造完全交由开发人士本身支配。在那一章,提出一个可能的点子来公司管制一个特大型应用程序的包和模块。那种结构将用于书中别的的示范中。

壹、项目组织

示例 基本多文本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应用1般放置在名字为app的目录下。
  • migrations目录包罗数据库迁移脚本,那和从前说的同样。
  • 单元测试放置在test目录下
  • venv目录包罗Python虚拟环境,这和事先说的也是同等的。

还有一对新的文书:

  • requirements.txt列出一些依靠包,那样就能够很不难的在不一样的微处理器上配备一个同等的虚拟环境。
  • config.py存款和储蓄了有个别配备安装。
  • manage.py用于运营应用程序和别的应用程序职务。

为了帮忙您一点1滴知道那些组织,上面会讲述将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基类包含部分1如既往配置;区别的子类定义不一致的布局。额外安顿能够在急需的时候在加盟。

数量与路由。为了让配置越来越灵敏更安全,壹些安装能够从环境变量中程导弹入。例如,SECRET_KEY,由于它的敏感性,能够在环境中装置,但1旦条件中平素不概念就无法不提供2个暗中认可值。

在五个布局中SQLALCHEMY_DATABASE_U昂科拉I变量能够分配差异的值。那样应用程序能够在差别的陈设下运维,各样能够使用差异的数据库。

配置类能够定义三个将应用程序实例作为参数的init_app()静态方法。那里一定于配置的最先化是足以实施的。那里Config基类完成三个空init_app()方法。

在安插脚本的平底,那些不一致的计划是登记在铺排字典中。将中间三个布局(开发配置)注册为私下认可配置。

三、应用程序包 应用程序包放置了拥有应用程序代码、模板和静态文件。它被归纳的名称为app,也足以给定2个一定于选择的名称(假如必要的话)。templates和static目录是应用的一部分,因而那多个目录应当放置在app中。数据库模型和电子邮件支持作用也要置入到那些包中,各种都是app/models.py和app/email.py情势存入本身的模块当中。

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

在单个文件中创建应用程序的主意特别有益,然而它有叁个大弱点。因为应用程序成立在大局范围,没有艺术动态的适应应用配置的改变:脚本运维时,应用程序实例已经创立,所以它早已来比不上更改配置。对于单元测试那是越发重大的,因为有时须要在分歧的安排下运营应用程序来取得更加好的测试覆盖率。

焚薮而田那1题目标诀窍正是将应用程序放入一个工厂函数中来延缓创制,这样就足以从剧本中显式的调用。

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

本条构造函数导入大部分当下内需动用的恢宏,但因为从没应用程序实例开首化它们,它能够被创制但不初步化通过不传递参数给它们的构造函数。create_app()即应用程序工厂函数,须求传入用于应用程序的布署名。配置中的设置被保留在config.py中的一个类中,能够使用Flask的app.config配置对象的from_object()方法来一直导入。配置对象足以经过对象名从config字典中选出。1旦应用程序被创制且布局好,扩充就足以被开端化。调用增添里的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

工厂函数重回创造的应用程序实例,可是请留心,在如今情景下利用工厂函数创造的应用程序是不完整的,因为它们未有路由和自定义错误页面处理程序。那是下一节的宗旨。

叁.2、在蓝图中落实应用程序的机能

应用程序工厂的转向工作引出了路由的复杂化。在单脚本应用中,应用程序实例是全局的,所以能够很不难地行使app.route装饰器定义路由。可是以后应用程序在运维时创设,app.route装饰器只有在create_app()调用后才起来存在,那就太迟了。就如路由那样,这么些通过app.errorhandler装饰器定义的自定义错误页面处理程序也设有同样的难题。

幸运的是Flask使用蓝图来提供二个越来越好的缓解方案。2个蓝图就好像于叁个得以定义路由的应用程序。差异的是,和路由相关联的蓝图都在蛰伏状态,唯有当蓝图在采纳中被登记后,此时的路由才会成为它的一某些。使用定义在大局意义域下的蓝图,定义应用程序的路由就差一些能够和单脚本应用程序壹样简单了。

和应用程序一样,蓝图能够定义在3个文件或三个包中与几个模块壹起创办更结构化的不二诀要。为了追求最大的灵活性,能够在应用程序包中创立子包来全部蓝图。下边展现了创办蓝图的构造函数。

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.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())

在蓝图中写视图函数有两大不一致点。第3,正如以前的错误处理一样,路由装饰器来自于蓝图。第三个分裂是url_for()函数的使用。你可能会想起,该函数的第三个参数为路由节点名,它给基于应用程序的路由内定暗许视图函数。例如,单脚本应用程序中的index()视图函数的U卡宴L能够通过url_for(‘index’)来获得。

差别的是Flask名称空间适用于来自蓝图的保有节点,那样七个蓝图能够利用同壹节点定义视图函数而不会发生争辨。名称空间正是蓝图名(Blueprint构造函数中的第8个参数),所以index()视图函数注册为main.index且它的U帕杰罗L可以透过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

当安装或更新3个包事后最棒再立异一下以此文件。以下展示了二个需要文件示例:

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文件中的版本号恐怕已经过时了。要是喜欢您能够品味用方今发表的包。若是遇上别的难点,你能够每十日回退到要求文件中与利用包容的内定版本。

陆、单元测试 那个应用尤其小以至于不须求太多的测试,可是作为示例会在示范中显得几个差不多的测试定义。

示例: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()方法在各种测试此前和将来运营,且任何3个办法必须以test_始于作为测试来推行。

建议:若是你想要学习越多选择Python的unittest包来写单元测试的始末,请参阅官方文档。
setUp()方法尝试创造二个测试环境,类似于运作应用程序。首先它创设应用程序配置用于测试并激活上下文。这一步确认保证测试能够和健康请求一样访问current_app。然后,当须求的时候,能够制造1个供测试使用的全新数据库。数据库和应用程序上下文子禽在tearDown()方法中被移除。

率先个测试确认保障应用程序实例存在。第一个测试确认保障应用程序在测试配置下运作。为了有限支撑tests目录有效,需求在tests目录下扩充__init__.py文件,但是该公文可以为空,那样unittest包能够扫描全体模块并稳定测试。

建议:借使你有仿制在GitHub上的应用程序,你以后得以运作git checkout
7a来切换成那个版本的应用程序。为了保障您早就设置了全体正视集,需求周转pip
install -r requirements.txt。
为了运营单元测试,能够在manage.py脚本中加进2个自定义的下令。

上面呈现什么添加测试命令。

以身作则: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

七、数据库运行 与单脚本的行使相比较,重构后的选择使用差别数据库。

从环境变量中获得的数据库U大切诺基L作为首要选用,暗中同意SQLite数据库作为可选。四个布局中的环境变量和SQLite数据库文件名是分歧等的。例如,开发配置的ULacrosseL是从DEV_DATABASE_UMuranoL环境变量中获得,假使未有概念则会动用名称为data-dev.sqlite的SQLite数据库。

任凭数据库UHavalL源的是哪一个,都必须为新的数据库创造数量库表。倘若采取了Flask-Migrate来保障迁移跟踪,数据库表能够被创制或更新到近期的本子通过上边包车型地铁指令:

(venv) $ python manage.py db upgrade

深信不疑与否,已经到了第二有的了结的地点。你将来早已学到了Flask须要的基本要素,但是你不分明什么将这个零碎的学问结合在联合署名形成四个当真的应用程序。第三部分的指标是因此开发三个完全的应用程序来教导你继续升高。

纵然小型web应用程序用单个脚本能够很有益于,但那种措施却无法很好地扩大…

flask是python的二个web应用框架,django很三个人听过,flask相比少见,连创办人一起头写出来只是个笑话而已,对python三支撑不太好,flask的好处是微应用,有要求的插件才使用,精简而灵活,由于灵活,要怎么开创三个品种要团结去商量怎么搭建,不像django帮你做完项目搭建的步骤。个人认为怎么搭建一个体系也是1个就学后台架构的历程。那里不会详细介绍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

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

  1. 蓝图,就是为了分模块的,比如二个web系统便是属于一个web模块,3个平移端选取的api就是3个api模块,而我们那里的book,user等不一样类其他py文件,倘诺每二个都注册三个蓝图的话就有点不乏先例了,所以要开始展览单蓝图
  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. 此间先创建三个伪代码user.py,为了多1个模块进行出现说法

# -*- 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. 上面包车型大巴代码都写到视图中那样不妥,展现不了封装性,看起来糟糕,应该把3个贯彻的成效封装起来,建立贰个函数,方便日后的管制
  2. 在目录下建立二个helper.py文本,这些文件重大正是提供部分方法,把地点的情节放到那里,只必要回到3个值就能够了

# -*- 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. 因为这一个体系要拜访分裂的网址,所以在目录下新建一个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 控制

伍、WTForms参数验证

  1. 上边大家把url改了,然而一旦用户输入了①部分出奇的标记该如何做?这一年就要动用到参数验证,而WTForms框架正是1个妙不可言的参数验证框架,首先在相应的环境中实行设置(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. 先是在目录下定义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文件之中创造蓝本,(蓝本和顺序类似,也能够定义路由。区别的是,在原本中定义的路由处于休眠状态,直到蓝本注册到程序上后,路由才真正变为程序的1有的。)main文件夹下views.py用来保存程序的路由,errors.py用来处理错误,forms.py是存放在表单定义。

    • init.py

      和路由相关联的蓝图都在蛰伏状态,唯有当蓝图在利用中被登记后,此时的路由才会成为它的一片段。使用定义在全局意义域下的蓝图,定义应用程序的路由就差不离能够和单脚本应用程序一样简单了。

      蓝图能够定义在一个文书或一个包中与八个模块一起创设更结构化的主意。为了追求最大的油滑,能够在应用程序包中创设子包来全数蓝图。

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

      蓝图是因此实例化Blueprint类对象来创制的。那几个类的构造函数接收七个参数:蓝图名和蓝图所在的模块或包的地方。与应用程序一样,在大多数景况下,对于首个参数值使用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
      

在蓝图中写视图函数有两大分歧点。第二,正如从前的错误处理一样,路由装饰器来自于蓝图。第二个例外是url_for()函数的施用。该函数的率先个参数为路由节点名,它给基于应用程序的路由钦定暗许视图函数。例如,单脚本应用程序中的index()视图函数的UEnclaveL能够由此url_for(‘index’)来获得。

Flask名称空间适用于来自蓝图的拥有节点,那样多少个蓝图能够运用同样节点定义视图函数而不会发出争执。名称空间正是蓝图名(Blueprint构造函数中的第2个参数),所以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的种种开头化。

    在单个文件中创立应用程序的办法丰富有利,但是它有二个大胜笔。因为应用程序创设在大局范围,未有办法动态的适应应用配置的改动:脚本运营时,应用程序实例已经创设,所以它已经来不如更改配置。化解那1标题标艺术正是将应用程序放入三个工厂函数中来贻误成立,那样就能够从剧本中显式的调用。那不光给脚本丰硕的时光来设置配置,也能用于创制多少个应用程序实例。

    那几个构造函数导入大多数当下亟待运用的恢弘,但因为未有应用程序实例初叶化它们,它可以被创制但不初叶化通过不传递参数给它们的构造函数。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的持筹握算是三个独自的逻辑,应该用封装成二个方法,使用的时候一贯调用

      # 获取每一页的起始下标
          @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. 一旦视图函数都写在主文件中,不便于维护,而是应当把他们放入到三个文本中,每2个模块正是3个打算,用的时候一直引用,那样便于保障
  2. 在根目录下树立3个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中涵盖二个基类Config定义,多个继续类定义DevlopmentConfig、TestingConfig、ProductionConfig和1个字典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基类包罗部分一模一样配置;分歧的子类定义分歧的布署。额外安顿能够在急需的时候在加盟。

为了让配置更加灵活更安全,一些装置能够从环境变量中程导弹入。例如,SECRET_KEY,由于它的敏感性,能够在条件中设置,但如果条件中一贯不定义就不可能不提供四个默许值。

在多个布局中SQLALCHEMY_DATABASE_URI变量能够分配不相同的值。那样应用程序能够在分裂的安插下运作,各类能够行使差异的数据库。

配置类能够定义3个将应用程序实例作为参数的init_app()静态方法。那里一定于配置的伊始化是足以实施的。这里Config基类完毕1个空init_app()方法。

在安插脚本的尾巴部分,这几个分歧的布局是注册在布局字典中(config)。将里面1个布置(开发配置)注册为暗中同意配置。

7、定义第三个模型类

  1. 咱俩今日把公文进行规整,如下:

亚洲必赢手机入口 3

  1. 率先在地面成立3个数据库,如下:

亚洲必赢手机入口 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. 亚洲必赢手机入口 5
  3. 漫天工艺流程中,出现了三遍主旨app对象的初始化,注册路由是在本白流程中初始化的app注册的。不过运行服务是新民主主义革命流程中的app运行的
  4. book中注册路由所利用的app对象,是她协调所导入fisher模块的app对象(浅莲红流程中),而不是乙亥革命主流程中所实例化的app对象
  5. 难题壹:因为都是由fisher引进book,二个模块只会引进另二个模块二回,所以只实行了3回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. 然后运营品种,就会创立在钦赐的数据库中开创2个数据表了,然而运转品种会现出上面包车型客车那种错误

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

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

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

亚洲必赢手机入口 6

发表评论

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

网站地图xml地图