多少与路由

黄金时代、应用、蓝图与视图函数

  1. 结构,如图:

    图片 1

  2. Flask最上层是app核心对象 ,在此个基本目的上得以插入比很多蓝图,那些蓝图是无法独立存在的,必须将app作为插板插入app ,在每三个蓝图上,可以挂号成百上千静态文件,视图函数,模板 ,四个工作模块能够做为八个蓝图,例如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'])

行使Python的Flask框架创设大型Web应用程序的组织示例,pythonflask

虽说Miniweb应用程序用单个脚本能够很便利,但这种办法却无法很好地扩展。随着应用变得复杂,在单个大的源文件中拍卖会变得难点重重。

与一大半别样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目录富含数据库迁移脚本,那和以前说的等同。
  • 单元测量试验放置在test目录下
  • venv目录饱含Python设想境况,那和后边说的也是均等的。

再有局地新的文本:

  • requirements.txt列出部分信任包,那样就足以超级轻便的在不相同的Computer上布置三个长久以来的设想情况。
  • config.py存款和储蓄了一些配置安装。
  • manage.py用于运行应用程序和其他应用程序任务。

为了辅助您一点一滴清楚这些组织,上边会陈说将hello.py应用改为顺应那蓬蓬勃勃构造的全方位工艺流程。

2、配置选项 应用程序平常要求多少个布局安装。最佳的事例便是在付出进程中供给利用分裂的数据库,测验,分娩情状,那样他们得以做到互不苦闷。

我们得以选用配置类的档期的顺序布局来代表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,由于它的敏感性,能够在境况中安装,但假诺条件中并未有概念就亟须提供四个默许值。

在多少个构造中SQLALCHEMY_DATABASE_URubiconI变量能够分配区别的值。那样应用程序能够在不一致的布置下运营,每一个能够行使分歧的数据库。

布置类能够定义三个将应用程序实例作为参数的init_app(卡塔尔静态方法。这里一定于配置的伊始化是能够举办的。这里Config基类实现二个空init_app()方法。

在安顿脚本的底层,这一个不一致的配置是注册在配备字典中。将里面一个安插(开荒配置)注册为暗中认可配置。

3、应用程序包 应用程序包放置了装有应用程序代码、模板和静态文件。它被略去的叫做app,也能够给定叁个特定于采取的称呼(若是需求的话卡塔尔(قطر‎。templates和static目录是利用的风流倜傥局地,因而那多少个目录应该放置在app中。数据库模型和电子邮件帮助作用也要置入到那些包中,各样都是app/models.py和app/email.py情势存入本身的模块当中。

3.1、使用叁个应用程序工厂

在单个文件中开创应用程序的办法非常便利,然而它有三个大毛病。因为应用程序创制在全局范围,未有章程动态的适应应用配置的校订:脚本运维时,应用程序实例已经创办,所以它曾经来比不上改进配置。对于单元测量试验这是特意主要性的,因为有的时候须求在不相同的构造下运作应用程序来获得越来越好的测量检验覆盖率。

消除那生机勃勃题指标主意正是将应用程序放入多个厂子函数中来延缓成立,那样就能够从剧本中显式的调用。

那不单给脚本足够的时间来安装配置,也能用于创制多少个应用程序实例——一些在测量试验进度中十分低价的事物。被定义在app包的布局函数中的应用程序工厂函数会在演示7-3中浮现。

本条布局函数导入大多数当下内需动用的强盛,但因为从没应用程序实例早先化它们,它能够被创建但不初始化通过不传递参数给它们的布局函数。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

工厂函数再次来到创设的应用程序实例,不过请小心,在当下气象下使用工厂函数创造的应用程序是缺损的,因为它们未有路由和自定义错误页面管理程序。那是下意气风发节的宗旨。

3.2、在蓝图中落实应用程序的成效

应用程序工厂的倒车工作引出了路由的复杂化。在单脚本应用中,应用程序实例是大局的,所以能够十分轻便地使用app.route装饰器定义路由。不过以往应用程序在运维时创造,app.route装饰器唯有在create_app(卡塔尔(قطر‎调用后才初始存在,那就太迟了。就像路由那样,这一个经过app.errorhandler装饰器定义的自定义错误页面处理程序也存在相近的难题。

侥幸的是Flask使用蓝图来提供贰个越来越好的建设方案。一个蓝图就相近于三个可以定义路由的应用程序。不相同的是,和路由相关联的蓝图都在蛰伏状态,唯有当蓝图在利用中被注册后,那个时候的路由才会成为它的一片段。使用定义在全局意义域下的蓝图,定义应用程序的路由就差了一些能够和单脚本应用程序相像轻便了。

和应用程序类似,蓝图能够定义在贰个文件或二个包中与五个模块一起建设更构造化的方法。为了追求最大的灵活性,能够在应用程序包中成立子包来全数蓝图。下边显示了创办蓝图的布局函数。

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

在蓝图中写视图函数有两大分裂点。第意气风发,正如早前的错误管理同样,路由装饰器来自于蓝图。第4个不等是url_for(卡塔尔(قطر‎函数的应用。你可能会想起,该函数的率先个参数为路由节点名,它给基于应用程序的路由钦定暗许视图函数。举例,单脚本应用程序中的index(卡塔尔视图函数的U福特ExplorerL能够通过url_for('index')来获得。

差异的是Flask名称空间适用于来自蓝图的装有节点,那样多少个蓝图能够接收同生龙活虎节点定义视图函数而不会时有发生冲突。名称空间便是蓝图名(Blueprint构造函数中的第八个参数),所以index(卡塔尔(قطر‎视图函数注册为main.index且它的UTucsonL能够因此url_for('main.index')获得。

在蓝图中,url_for(卡塔尔(英语:State of Qatar)函数相似支撑越来越短格式的节点,省略蓝图名,比方url_for('.index'卡塔尔国。有了那个,就足以这样使用当前恳请的蓝图了。那实际意味着相仿蓝图内的重定向可以行使越来越短的情势,假诺重定向跨蓝图则必得选用带名称空间的节点名。

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

4、运转脚本 顶层目录中的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。

5、须求文件 应用程序必需带有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文件中的版本号或然早就过时了。即便心仪您能够尝尝用近期发表的包。要是蒙受别的难题,你能够每天回落到供给文件中与利用宽容的内定版本。

6、单元测验 那么些应用超级小以至于无需太多的测量试验,但是作为示例会在示范中显示五个大致的测量试验定义。

示例: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_起来作为测量试验来施行。

提出:纵然你想要学习更Dolly用Python的unittest包来写单元测量检验的剧情,请参阅官方文书档案。
setUp(卡塔尔方法尝试创设二个测验情形,形似于运作应用程序。首先它创制应用程序配置用于测量检验并激活上下文。这一步确认保障测量试验能够和例行诉求雷同访问current_app。然后,当必要的时候,能够创制三个供测验使用的全新数据库。数据库和应用程序上下文种在tearDown(卡塔尔(英语:State of Qatar)方法中被移除。

率先个测量试验确定保障应用程序实例存在。首个测量检验确认保障应用程序在测验配置下运作。为了保证tests目录有效,供给在tests目录下扩张__init__.py文件,然而该公文可认为空,那样unittest包能够扫描所有模块并一直测量试验。

提出:假设您有克隆在GitHub上的应用程序,你今后能够运转git checkout 7a来切换来那一个本子的应用程序。为了保险您已经安装了具备依赖集,需求周转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

7、数据库运维 与单脚本的行使比较,重构后的行使使用差别数据库。

从处境变量中拿走的数据库U奥迪Q5L作为主要推荐,暗中认可SQLite数据库作为可选。七个构造中的境遇变量和SQLite数据库文件名是不等同的。举例,开拓配置的USportageL是从DEV_DATABASE_UPRADOL蒙受变量中收获,若无概念则会接纳名字为data-dev.sqlite的SQLite数据库。

无论数据库UTucsonL源的是哪三个,都必需为新的数据库创造数量库表。假诺采用了Flask-Migrate来保持迁移追踪,数据库表能够被创建或更新到近些日子的本子通过下边包车型地铁命令:

(venv) $ python manage.py db upgrade

深信与否,已经到了第意气风发有个别竣事的地点。你现在早就学到了Flask必要的基本要素,可是你不鲜明如何将这么些碎片的学识结合在一同形成二个的确的应用程序。第二部分的指标是通过支付二个整机的应用程序来指点你世襲提升。

即便Miniweb应用程序用单个脚本能够很有利,但这种艺术却不可能很好地增加...

flask是python的叁个web应用框架,django很四人听过,flask少之甚少见,连开创者生龙活虎初步写出来只是个笑话而已,对python3支撑不太好,flask的益处是微应用,有必要的插件才使用,简练而灵活,由于灵活,要怎么开创一个种类要和睦去构思怎么搭建,不像django帮你做完项目搭建的步调。个人认为怎么搭建一个品类也是二个就学后台布局的长河。这里不会详细介绍flask和flask各样模块的效果与利益,留作考虑与读书。

数据

图书数据库的地点

# 基地址
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

二、用蓝图注册视图函数

  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)
|-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. 依据下边包车型大巴地点能够知晓寻找的时候有三种办法,而对此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. 多逻辑推断的时候,应该把结果望着为假的嵌入前面,对数据库操作的放置前面,那样有扶植节约财富

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

  1. 蓝图,便是为了分模块的,举例二个web系统便是归属叁个web模块,一个运动端选用的api正是三个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,为了多三个模块举办身体力行
# -*- 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. 在目录下创立三个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乞求触发的函数或视图函数中动用
  • app的目录下是放Flask应用
  • migrations目录包蕴数据库迁移脚本
  • test目录下是放单元测量试验
  • venv是Python设想情况
  • requirements.txt是Python运维的重视包列表
  • config.py是安排安装脚本
  • manage.py 用于运转应用程序和其他应用程序任务
  • command.py 控制

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 ''

五、WTForms参数验证

  1. 上边大家把url改了,可是假设顾客输入了有的新鲜的号子该如何做?这时就要动用到参数验证,而WTForms框架正是一个上佳的参数验证框架,首先在相应的蒙受中开展设置(flask--yQglGu4) E:pyqiyueflask>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':'参数校验失败'})

app层

app上边有main、static、templates八个文件夹以至init.py、email.py、models.py

  • main文本夹用来保存蓝本,此文件夹下 init.py文件之中创设蓝本,(蓝本和次序相通,也得以定义路由。不一样的是,在原来中定义的路由处于休眠状态,直到蓝本注册到程序上后,路由才真正成为程序的后生可畏都部队分。)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(卡塔尔(英语:State of Qatar)函数的运用。该函数的第一个参数为路由节点名,它给基于应用程序的路由钦赐暗许视图函数。比方,单脚本应用程序中的index(卡塔尔视图函数的U奥迪Q7L能够通过url_for('index')来获得。

Flask名称空间适用于来自蓝图的装有节点,那样几个蓝图能够选取同生龙活虎节点定义视图函数而不会发出冲突。名称空间正是蓝图名(Blueprint结构函数中的第二个参数),所以index(卡塔尔国视图函数注册为main.index且它的UGL450L能够透过url_for(main.index)获得。

rl_for(卡塔尔(قطر‎函数相同支撑更加短格式的节点,省略蓝图名,举例url_for('.index'卡塔尔(英语:State of Qatar)。有了这么些,就足以这么使用当前恳请的蓝图了。那其实意味着相仿蓝图内的重定向能够动用更加短的花样,倘使重定向跨蓝图则必得选拔带名称空间的节点名。

做到了应用程序页面改正,表单对象也保存在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(卡塔尔发送文书函数(异步卡塔尔(英语:State of Qatar)

  • models.py带有User和Role三个表定义

从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'])

六、拆分配置文件

  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)

config.py 应用配置示范

config.py中富含一个基类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基类包蕴部分相仿配置;分化的子类定义区别的陈设。额外安顿能够在须要的时候在投入。

为了让配置越来越灵活更安全,一些设置能够从境况变量中程导弹入。举个例子,SECRET_KEY,由于它的敏感性,能够在条件中安装,但要是条件中绝非定义就必须要提供多少个暗许值。

在八个布局中SQLALCHEMY_DATABASE_URI变量能够分配不相同的值。那样应用程序能够在分化的布置下运营,每一个能够使用分裂的数据库。

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

在构造脚本的底层,这一个不一样的安插是挂号在安排字典中(config卡塔尔。将内部叁个配置(开采配置卡塔尔(قطر‎注册为暗中同意配置。

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

  1. 比如视图函数都写在主文件中,不便于维护,而是应该把他们放入到一个文书中,每一个模块正是多少个试图,用的时候从来引用,那样有助于爱慕
  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. 但是那样写的话,见面世404,因为现身了循环引用

七、定义第三个模型类

  1. 我们前日把公文进行整合治理,如下:

图片 3

  1. 首先在地头创设八个数据库,如下:

图片 4

  1. 在app/models/book.py文件中国建工业总会公司立模型,这里运用到sqlalchemy来贯彻自动化映射,在Flask框架中对那么些进行了改正Flask_SQLAlchemy,那么些特别人性化,安装(flask--yQglGu4) E:pyqiyueflask>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

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三次开头化,如图
  2. 图片 5
  3. 漫天工艺流程中,现身了两回核心app对象的起头化,注册路由是在杏黄流程中开端化的app注册的。可是运营服务是革命流程中的app运行的
  4. book中注册路由所使用的app对象,是他本身所导入fisher模块的app对象(绿色流程中),实际不是新民主主义革命主流程中所实例化的app对象
  5. 主题素材1:因为都以由fisher引进book,七个模块只会引进另两个模块三回,所以只进行了一次book
  6. 难题2:由于一遍是主流程施行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

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

  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),那样就足以了,在数据库中就足以看看表了

图片 6

本文由星彩网app下载发布于计算机编程,转载请注明出处:多少与路由

TAG标签: 星彩网app下载
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。