djangoでfactory_boyを使ってみる

軽くさわってみて雰囲気をみてみた

factory_boy ― Factory Boy 2.1.2 documentation
rbarrois/factory_boy

インストール

$ pip install factory_boy

こんなエラーがでたけど、pip install -U setuptoolsしてリトライしたら成功した

pkg_resources.VersionConflict: (setuptools 0.6c11 (/Users/yuhei/.virtualenvs/django15/lib/python2.7/site-packages/setuptools-0.6c11-py2.7.egg), Requirement.parse('setuptools>=0.8'))

Factoryの定義

モデルのサンプル

from django.db import models


class User(models.Model):
    firstname = models.CharField(max_length=100)
    lastname = models.CharField(max_length=100)


Factoryクラス。djangoの場合、継承するのはfactory.Factoryではなくて、factory.django.DjangoModelFactory。
最初間違ってfactory.Factoryにしてたら、createしてもデータがsaveされなかった。

import factory
from . import models


class UserFactory(factory.django.DjangoModelFactory):
    FACTORY_FOR = models.User

    firstname = "taro"
    lastname = "yamada"

使えそうな機能を適当にいろいろ試した

class UserFactory(factory.django.DjangoModelFactory):
    FACTORY_FOR = models.User

    firstname = "taro"
    lastname = "yamada"

    # 直接関数を書いても大丈夫
    gender = random.choice([1, 2])

    # シーケンス
    unique_id = factory.Sequence(lambda n: 'user%d' % n) 

    # ImageFieldやFileFieldに値を入れるためのクラスがある
    # https://factoryboy.readthedocs.org/en/latest/orms.html#factory.django.ImageField
    icon = factory.django.ImageField()

    # lazy_attribute
    email = factory.LazyAttribute(lambda obj: '%s.%s@example.com' % (obj.firstname, obj.lastname))

    # lazy_attribute2
    @factory.lazy_attribute
    def email2(self):
        return '%s.%s@example.com' % (self..firstname, self..lastname)

関連しているモデルをまとめて作れる

class Post(models.Model):
    content = models.CharField(max_length=100)
    author = models.ForeignField(User)


class PostFactory(factory.django.DjangoModelFactory):
    FACTORY_FOR = Post
    content = "dummy_content"
    author = factory.LazyAttribute(lambda a: UserFactory())    
    # こう書いてもいいみたい   
    # author = factory.SubFactory(UserFactory)

Factoryを使う

Factoryを使うときに、saveする、しないを決められる

# デフォルトの挙動はsave済みのオブジェクトを返す。
user = UserFactory(firstname='taro')

# 明示的にsaveする
user = UserFactory.create()

# saveしないで返す
user = UserFactory.build()

感想

他にもいろいろ機能あるけど、とりあえず使いはじめるまでの学習コストは高くなさそう