『Flask Web Development』第5章データベース

8921 ワード

SQL Databases
特徴は何ですか.(空き補充)
NoSQL Databases
特徴は何ですか.(空き補充)
SQL or NoSQL?
それぞれの強みは何ですか?(空き補充)
Python Database Frameworks
  • どのデータベースを使用することができますか.オープンソースのデータベースかどうかにかかわらず、FlaskにはMySQL、Postgres、SQLite、Redis、MongoDB、CouchDBなどのデータベースエンジンに対応するpackageがあります.
  • これらが足りない場合は、SQLAlchemy、MongoEngineなどのデータベース抽象層packageを使用して、table、document、query languagesではなく、より高い階層でデータを操作することができます.
  • データベースの選択基準
  • 使いやすさ:SQL Vs NoSQL、後者は当然
  • に完勝した
  • 効率:後者はオブジェクトからデータベースモデルへの変換に一定のオーバーヘッドがあるが、これは無視でき、逆に、後者は生成率の促進によるオーバーヘッドをはるかに上回っている.
  • 移植性:多くのデータベース抽象層は1つのデータベースのサポートしか提供していませんが、SQLAlchemy ORMなど、より高いレベルのデータベース抽象層はほとんどすべてのデータベースをサポートしています.
  • Flask統合:Flaskのextensionとして存在すれば、手書きのコードを多く省くことができます.

  • 本書で選択したデータベースをまとめると、本書はFlask-SQLAlchemy(SQLAlchemyの拡張として)をデータベースツールとして選択しています.

  • Flask-SQLAlchemyによるデータベース管理
    Flask-SQLAlchemyはSQLAlchemyを使用した拡張子です.SQLAlchemyは強力なリレーショナル・データベース・フレームワークであり、複数のデータベースをサポートし、上位レベルのORMと下位レベルのオリジナル・データベース・オペレーションを提供します.
  • 取付
  • (venv) $ pip install flask-sqlalchemy
    
  • データベースURL Flask-SQLAlchemyでは、データベースはURLとして表示され、以下に示すようにMySQLmysql://username:password@hostname/database Postgres postgresql://username:password@hostname/database SQLite (Unix) sqlite:////absolute/path/to/database SQLite (Windows) sqlite:///c:/absolute/path/to/databasehostnameはホスト、username、passwordに対応しています.sqliteデータベースにはユーザー名パスワードがないので、ディレクトリの下のファイルにすぎません.
  • 構成データベースURLは、SQLALCHEMY_に配置されている.DATABASE_URI、もう一つの重要な属性はSQLALCHEMY_に配置されています.COMMIT_ON_TEARDOWN(通常はTrueに設定されている)
  • の例は、SQLiteデータベースを構成する例であり、dbはSQLAlchemyオブジェクトをインスタンス化し、すべてのFlask-SQLAlchemyが備える機能を提供する:
  • import os
    #..
    from flask.ext.sqlalchemy import SQLAlchemy
    basedir = os.path.abspath(os.path.dirname(__file__))
    app = Flask(__name__)
    app.config['SQLALCHEMY_DATABASE_URI'] =\
        'sqlite:///' + os.path.join(basedir, 'data.sqlite')
    app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
    db = SQLAlchemy(app)
    

    Model定義
    class Role(db.Model):
        __tablename__ = 'roles'
        id = db.Column(db.Integer, primary_key=True) 
        name = db.Column(db.String(64), unique=True)
    
        def __repr__(self):
            return '' % self.name
    
    class User(db.Model):
        __tablename__ = 'users'
        id = db.Column(db.Integer, primary_key=True)
        username = db.Column(db.String(64), unique=True, index=True)
        
        def __repr__(self):
            return '' % self.username
    

    クラス変数_tablename__ テーブル名が定義(デフォルトでは名前が付いていますが、非複素形ではよくありません)、すべての属性がdbとして定義.Columnのインスタンスオブジェクト、db.Columnの最初のパラメータはカテゴリです.2番目のパラメータはオプションの構成パラメータです(すべてのtableにprimary keyが必要です).repr__()メソッドは、デバッグやテストを容易にするためです.
    Relationships
    次の例では、一対多の関係(構成の理解が深くない場合はそのまま書きましょう!)を示します.この本はdbをリストした表を付録した.relationshipでよく使用される構成パラメータの説明は、必要に応じて参照してください.
    class Role(db.Model): 
        # ...
        users = db.relationship('User', backref='role')
    
    class User(db.Model):
        # ...
        role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
    

    データベース操作
    これらのデータベース操作を学習する最善の方法は、Python Shellで、以下のセクションで最も一般的なデータベース操作の学習を開始することです(この章の前のモデルを構築するコードはhello.pyに適用されます):
    # shell      flask-script,create_all      model
    (venv) $ python hello.py shell 
    >>> from hello import db
    >>> db.create_all()
    
    #           drop     
    >>> db.drop_all()
    >>> db.create_all()
    
    >>> from hello import Role, User
    >>> admin_role = Role(name='Admin')
    >>> mod_role = Role(name='Moderator')
    >>> user_role = Role(name='User')
    >>> user_john = User(username='john', role=admin_role) 
    >>> user_susan = User(username='susan', role=user_role) 
    >>> user_david = User(username='david', role=user_role)
    
    #     commit         id
    >>> print(admin_role.id) None
    >>> print(mod_role.id) None
    >>> print(user_role.id) None
    
    #  db.session        
    >>> db.session.add(admin_role)
    >>> db.session.add(mod_role)
    >>> db.session.add(user_role)
    >>> db.session.add(user_john)
    >>> db.session.add(user_susan)
    >>> db.session.add(user_david)
    
    >>> db.session.commit()
    
    #           
    >>> print(admin_role.id) 1
    >>> print(mod_role.id) 2
    >>> print(user_role.id) 3
    
    #     
     >>> admin_role.name = 'Administrator'
    >>> db.session.add(admin_role)
    >>> db.session.commit()
    
    #   
    >>> db.session.delete(mod_role)
    >>> db.session.commit()
    
    #   
     >>> Role.query.all()
    [, ]
    >>> User.query.all()
    [, , ]
    
    #    
     >>> User.query.filter_by(role=user_role).all()
    [, ]
    
    #               ,             ,  page61.
    
    #              
    >>> str(User.query.filter_by(role=user_role))
    'SELECT users.id AS users_id, users.username AS users_username,
    users.role_id AS users_role_id FROM users WHERE :param_1 = users.role_id'
    
    #   ,   shell    ,       import db、Role,            ,  :
    >>> from hello import db
    >>> from hello import Role
    >>> user_role = Role.query.filter_by(name='User').first()
    
    #     
     >>> users = user_role.users
    >>> users
    [, ]
    >>> users[0].role
    
    
    #     ,      filter    。  user_role.usres     all()  ,   filter   py     :
    
    class Role(db.Model): 
    # ...
    users = db.relationship('User', backref='role', lazy='dynamic') 
    # ...
    
    >>> user_role.users.order_by(User.username).all()
    [, ]
    >>> user_role.users.count()
    2
    

    Python Shell統合Model
    Shellを開くたびに手動でインポートするのは面倒ですが、Flask-Scriptでは、オブジェクトを自動的にインポートできる構成が用意されています.
    from flask.ext.script import Shell
    def make_shell_context():
        return dict(app=app, db=db, User=User, Role=Role)
    
    manager.add_command("shell", Shell(make_context=make_shell_context))
    

    ViewFunctionsでのデータベースの操作
    データベース操作をViewFunctionに適用する例は次のとおりです.
    index.py
    @app.route('/', methods=['GET', 'POST'])
    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
            else:
                session['known'] = True
    
            session['name'] = form.name.data
            form.name.data = ''
    
            return redirect(url_for('index'))
        return render_template('index.html',
            form = form, name = session.get('name'), known = session.get('known', False))
    

    templates/index.html
    {% extends "commonBase.html" %}
    {% import "bootstrap/wtf.html" as wtf %}
    
    {% block title %}Flasky{% endblock %}
    
    {% block page_content %}
        
        {{ wtf.quick_form(form) }}
    {% endblock %}
    

    Flask-Migrarateを使用してデータベースのMigrationsを作成
    開発が一定の段階に進むと、モデルの構造が変更される必要があることがわかります.Flask-SQLAlchemyがモデルからデータベースを構築するテーブル構造は、以前のテーブルが存在しなかった場合にのみ発生します.もちろん、データの損失にかかわらずデータベースを削除することもできます.
    より良い方法は、コードがバージョン管理できるように、データベース移行フレームワークを使用して、データベースの変化を追跡し、データベースの変化を漸進的に適用することです.
    SQLAlchemyの開発者はAlembicというフレームワークを書いたが、直接使用するつもりはなく、Flask-Migrate extension拡張を使用してFlask-Scriptと統合し、すべてコマンドラインで目的を達成する.
    Creating a Migration Repository
    (venv) $ pip install flask-migrate
    

    拡張の構成方法を以下に示します.
    from flask.ext.migrate import Migrate, MigrateCommand 
    # ...
    migrate = Migrate(app, db)
    manager.add_command('db', MigrateCommand)
    

    dbのサブコマンドを使用してリポジトリを構築します.
      (venv) $ python index.py db init
    

    Creating a Migration Script
    Alembic migrationsは、手動と自動の2つのモードで使用できます.
    手動のmigrationで空のツールメソッドupgrade()とdowngrade()を作成すると、自動migrationは現在のデータベースとmodel definitionsの違いを自動的に検索してupgrade()とdowngrade()を完了します.
    自動migrationの例:
    (venv) $ python index.py db migrate -m "initial migration"
    

    Upgrading the Database
    migrationが完了するとdb upgradeでデータベースを更新できますdataをsqlite削除後にコマンドを実行します.
    (venv) $ python hello.py db upgrade
    

    全書を貫くとmigrationをめぐって進みますが、本書は簡単に紹介するだけで、後にもっと詳しい内容があります.