暗号通貨.py

ビットコインやブロックチェーンの技術に衝撃を受け、プログラミングの勉強を開始。現在はPythonを勉強中。

Python

Pyramidチュートリアルを辿る⑤Modelの編集

前回の続きです。

前回はルーティングについて学びました。続いて今回はModelについてです。

チュートリアルのこのページの後半部分ですね。

modelsフォルダには以下の3つのファイルが格納されています。

  • __init__.py
  • meta.py
  • mymodel.py

チュートリアルでもこの時点では変更せず、説明だけなのでサッといきます。

models/meta.py

SQLAlchemyベースのアプリケーションでは、モデルオブジェクトはSQLデータベースを照会して作成されたオブジェクトです。

modelsフォルダに実装するクラスを置きます。

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.schema import MetaData

# Recommended naming convention used by Alembic, as various different database
# providers will autogenerate vastly different names making migrations more
# difficult. See: http://alembic.zzzcomputing.com/en/latest/naming.html
NAMING_CONVENTION = {
    "ix": 'ix_%(column_0_label)s',
    "uq": "uq_%(table_name)s_%(column_0_name)s",
    "ck": "ck_%(table_name)s_%(constraint_name)s",
    "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
    "pk": "pk_%(table_name)s"
}

metadata = MetaData(naming_convention=NAMING_CONVENTION)
Base = declarative_base(metadata=metadata)

Alembicで使われている命名規則を推奨します、とコメントにありますが、「Alembic」とはいったいなんでしょう?

親切にURLを残してくれています。

http://alembic.zzzcomputing.com/en/latest/naming.html

日本語ではコチラの記事が詳しいです。

Alembic でデータベースのスキーマ変更を自動検出する

要はPython で書かれたデータベースマイグレーションツールのようです。

命名規則はそのAlembicで使われているものを使ったほうが良いということですね。

あとからファイルを削除したり追加したりするのでとりあえず次のページにいきます。

http://docs.pylonsproject.org/projects/pyramid/en/latest/tutorials/wiki2/definingmodels.html

setup.pyに'bcrypt'を追加する

bcryptというハッシュ関数によりパスワードを安全に保管するためのライブラリがあります。

この記事が詳しかったです。

Pythonでbcryptを使ってパスワードをゆっくりハッシュ化

ビットコインなどで使われているSHA-256との比較も書かれていています。

新しくライブラリをインストールするので'bcrypt'をsetup.pyに追記します。

import os

from setuptools import setup, find_packages

here = os.path.abspath(os.path.dirname(__file__))
with open(os.path.join(here, 'README.txt')) as f:
    README = f.read()
with open(os.path.join(here, 'CHANGES.txt')) as f:
    CHANGES = f.read()

requires = [
    'bcrypt',  #追記部分
    'pyramid',
    'pyramid_jinja2',
    'pyramid_debugtoolbar',
    'pyramid_tm',
    'SQLAlchemy',
    'transaction',
    'zope.sqlalchemy',
    'waitress',
]

tests_require = [
    'WebTest >= 1.3.1',  # py3 compat
    'pytest',
    'pytest-cov',
]

setup(
    name='myproject',
    version='0.0',
    description='tutorial',
    long_description=README + '\n\n' + CHANGES,
    classifiers=[
        'Programming Language :: Python',
        'Framework :: Pyramid',
        'Topic :: Internet :: WWW/HTTP',
        'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
    ],
    author='',
    author_email='',
    url='',
    keywords='web pyramid pylons',
    packages=find_packages(),
    include_package_data=True,
    zip_safe=False,
    extras_require={
        'testing': tests_require,
    },
    install_requires=requires,
    entry_points={
        'paste.app_factory': [
            'main = myproject:main',
        ],
        'console_scripts': [
            'initialize_myproject_db = myproject.scripts.initializedb:main',
        ],
    },
)

インストールしましょう。

$ pip install -e .

Successfully installed bcrypt-3.1.3 cffi-1.9.1 myproject pycparser-2.17

最後に.を入れることに注意です。

スポンサーリンク

adsense

スポンサーリンク

Modelの編集

 

models/mymodel.pyは使わないので削除します。

 

models/user.pyの作成

 

新しくuser.pyファイルを作ります。

先程インストールしたbcryptを使いベースとなるモデルを作成します。

import bcrypt
from sqlalchemy import (
    Column,
    Integer,
    Text,
)

from .meta import Base


class User(Base):
    """ The SQLAlchemy declarative model class for a User object. """
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(Text, nullable=False, unique=True)
    role = Column(Text, nullable=False)

    password_hash = Column(Text)

    def set_password(self, pw):
        pwhash = bcrypt.hashpw(pw.encode('utf8'), bcrypt.gensalt())
        self.password_hash = pwhash.decode('utf8')

    def check_password(self, pw):
        if self.password_hash is not None:
            expected_hash = self.password_hash.encode('utf8')
            return bcrypt.checkpw(pw.encode('utf8'), expected_hash)
        return False

models/page.py


page.pyも追加します。

from sqlalchemy import (
    Column,
    ForeignKey,
    Integer,
    Text,
)
from sqlalchemy.orm import relationship

from .meta import Base


class Page(Base):
    """ The SQLAlchemy declarative model class for a Page object. """
    __tablename__ = 'pages'
    id = Column(Integer, primary_key=True)
    name = Column(Text, nullable=False, unique=True)
    data = Column(Text, nullable=False)

    creator_id = Column(ForeignKey('users.id'), nullable=False)
    creator = relationship('User', backref='created_pages')

models/__init__.pyの編集

mymodel.pyを削除し、新しくuser.py、page.pyという2つのファイルを追加したのでクラスのimportなどを整理します。

  • from .mymodel import MyModelを削除
  • from .page import Page
    from .user import User を追記

scripts/initializedb.pyの編集


import os
import sys
import transaction

from pyramid.paster import (
    get_appsettings,
    setup_logging,
    )

from pyramid.scripts.common import parse_vars

from ..models.meta import Base
from ..models import (
    get_engine,
    get_session_factory,
    get_tm_session,
    )
# from ..models import MyModel 最初から入っている、削除
from ..models import Page, User



def usage(argv):
    cmd = os.path.basename(argv[0])
    print('usage: %s <config_uri> [var=value]\n'
          '(example: "%s development.ini")' % (cmd, cmd))
    sys.exit(1)


def main(argv=sys.argv):
    if len(argv) < 2:
        usage(argv)
    config_uri = argv[1]
    options = parse_vars(argv[2:])
    setup_logging(config_uri)
    settings = get_appsettings(config_uri, options=options)

    engine = get_engine(settings)
    Base.metadata.create_all(engine)

    session_factory = get_session_factory(engine)

    with transaction.manager:
        dbsession = get_tm_session(session_factory, transaction.manager)

        editor = User(name='editor', role='editor')
        editor.set_password('editor')
        dbsession.add(editor)

        basic = User(name='basic', role='basic')
        basic.set_password('basic')
        dbsession.add(basic)

        page = Page(
            name='FrontPage',
            creator=editor,
            data='This is the front page',
        )
        dbsession.add(page)


19行目のPageとUserのimport文と

46行目のeditor = 以降が変更ポイントです。

データベースを変更したので再度初期化します。

$ initialize_myproject_db development.ini

続けてサーバーを起動して現状を確認します。

$ pserve development.ini --reload

チュートリアル通りに進めているとImportErrorになります。

ImportError: cannot import name 'MyModel'

テストも試してみます。

$ py.test -q

_________________ ERROR collecting myproject/views/default.py __________________
ImportError while importing test module '/Users/maedanaoki/Documents/python_app/pyramid_tutorials/myproject/myproject/views/default.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
myproject/views/default.py:6: in
from ..models import MyModel
E ImportError: cannot import name 'MyModel'
!!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!!!
1 error in 1.85 seconds

なんかめっちゃ怒られました。笑

続きは次回に。

日本で一番簡単にビットコインが買える取引所 coincheck bitcoin

-Python