Flask仮想データの作成


Flask開発では、ページング機能の実装など、大量のデータを含むデータベースが必要になることが多い.データベース・レコードを手動で追加するのは時間がかかり、面倒なので、自動化スキームを使用することが望ましい.複数のPythonパッケージを使用して仮想情報を生成できます.ここで、機能が比較的完備しているForgeryPyはpipを使用してインストールできます.
<span style="font-size:18px;">(venv) $ pip install forgerypy</span>

        開発過程でしか使用されていないため、厳密にはForgeryPyはこのプログラムの依存ではありません.本番環境の依存性と開発環境の依存性を区別するために、ファイルrequirements.txtをrequirementsフォルダに変更し、それぞれ異なる環境での依存性を保存できます.この新しいフォルダでは、dev.txtファイルを作成し、開発中に必要な依存をリストし、prod.txtファイルを作成し、本番環境に必要な依存をリストできます.
       2つの環境で必要な依存度の大部分は同じであるため、dev.txtおよびprod.txtで-rパラメータを使用してインポートするcommon.txtファイルを作成できます.
requirements/common.txt
Flask==0.10.1
Flask-Bootstrap==3.0.3.1
Flask-HTTPAuth==2.7.0
Flask-Login==0.3.1
Flask-Mail==0.9.0
Flask-Migrate==1.1.0
Flask-Moment==0.2.1
Flask-PageDown==0.1.4
Flask-SQLAlchemy==1.0
Flask-Script==0.6.6
Flask-WTF==0.9.4
Jinja2==2.7.1
Mako==0.9.1
Markdown==2.3.1
MarkupSafe==0.18
SQLAlchemy==0.9.9
WTForms==1.0.5
Werkzeug==0.10.4
alembic==0.6.2
bleach==1.4.0
blinker==1.3
html5lib==1.0b3
itsdangerous==0.23
six==1.4.1
requirements/dev.txt:         
-r common.txt
ForgeryPy==0.1
requirements/prod.txt:         
-r common.txt
 
  
 

如下展示了添加到 User 模型类方法,用来生成虚拟数据。

class User(UserMixin, db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(64), unique=True, index=True)
    username = db.Column(db.String(64), unique=True, index=True)
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
    password_hash = db.Column(db.String(128))
    confirmed = db.Column(db.Boolean, default=False)
    name = db.Column(db.String(64))
    location = db.Column(db.String(64))
    about_me = db.Column(db.Text())
    member_since = db.Column(db.DateTime(), default=datetime.utcnow)
    last_seen = db.Column(db.DateTime(), default=datetime.utcnow)
    avatar_hash = db.Column(db.String(32))
    posts = db.relationship('Post', backref='author', lazy='dynamic')
    followed = db.relationship('Follow',
                               foreign_keys=[Follow.follower_id],
                               backref=db.backref('follower', lazy='joined'),
                               lazy='dynamic',
                               cascade='all, delete-orphan')
    followers = db.relationship('Follow',
                                foreign_keys=[Follow.followed_id],
                                backref=db.backref('followed', lazy='joined'),
                                lazy='dynamic',
                                cascade='all, delete-orphan')
    comments = db.relationship('Comment', backref='author', lazy='dynamic')


    <strong>@staticmethod
    def generate_fake(count=100):
        from sqlalchemy.exc import IntegrityError
        from random import seed
        import forgery_py

        seed()
        for i in range(count):
            u = User(email=forgery_py.internet.email_address(),
                     username=forgery_py.internet.user_name(True),
                     password=forgery_py.lorem_ipsum.word(),
                     confirmed=True,
                     name=forgery_py.name.full_name(),
                     location=forgery_py.address.city(),
                     about_me=forgery_py.lorem_ipsum.sentence(),
                     member_since=forgery_py.date.date(True))
            db.session.add(u)
            try:
                db.session.commit()
            except IntegrityError:
                db.session.rollback()</strong>

仮想データを生成するためにPostモデルクラスに追加する方法を以下に示す.
class Post(db.Model):
    __tablename__ = 'posts'
    id = db.Column(db.Integer, primary_key=True)
    body = db.Column(db.Text)
    body_html = db.Column(db.Text)
    timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
    author_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    comments = db.relationship('Comment', backref='post', lazy='dynamic')

    <strong>@staticmethod
    def generate_fake(count=100):
        from random import seed, randint
        import forgery_py

        seed()
        user_count = User.query.count()
        for i in range(count):
            u = User.query.offset(randint(0, user_count - 1)).first()
            p = Post(body=forgery_py.lorem_ipsum.sentences(randint(1, 5)),
                     timestamp=forgery_py.date.date(True),
                     author=u)
            db.session.add(p)
            db.session.commit()</strong>

        これらの仮想オブジェクトの属性はForgeryPyのランダム情報生成器によって生成され、名前、電子メールアドレス、文などの属性は本物のように見えます.ユーザーのEメールアドレスとユーザー名は一意でなければなりませんが、ForgeryPyはこれらの情報をランダムに生成するため、重複するリスクがあります.このような不可能な状況が発生した場合、データベース・セッションのコミット時にIntegratyError例外が放出されます.この例外の処理は、操作を続行する前にセッションをロールバックすることです.ループ中に重複コンテンツが生成されると、ユーザーはデータベースに書き込まれないため、生成される仮想ユーザーの総数は予想より少なくなる可能性があります.ランダムに文章を生成するときは、各文章にランダムにユーザーを指定します.このためoffset()クエリーフィルタを使用します.このフィルタは、パラメータで指定したレコードの数をスキップします.ランダムなオフセット値を設定してfirst()メソッドを呼び出すことで、毎回異なるランダムユーザを得ることができます.
      新しく追加された方法では、Python shellで多くの仮想ユーザーと記事を簡単に生成できます.
(venv) $ python manage.py shell
>>> User.generate_fake(100)
>>> Post.generate_fake(100)