以下のような、「本」と「本の種別(マスターデータ)」を表すModelがあるとする。
class BookCategory(models.Model): name = models.TextField() class Book(models.Model): name = models.TextField() book_category = models.ForeignKey(BookCategory, on_delete=models.DO_NOTHING)
実データの例は以下のような感じ。
ER図にすると以下のようになる。
BookのレコードをFactory Boyで作りたいとする。
単純に作ると、以下のようになる。
class BookFactory(DjangoModelFactory): class Meta: model = models.Book name = "Test Name" book_category = BookCategory.objects.get(name='comic')
この例では、book_categoryのデフォルト値を'comic'のレコードにしている。
ただ、ユニットテストではカテゴリを色々と変えてレコードを作りたい。
# カテゴリがデフォルトの'comic'ならこれでいいけど book1 = BookFactory.create() # 別のカテゴリを設定したいときは、マスターデータを取得してくる必要がある。ちょっと面倒。 category = BookCategory.objects.get(name='science') book2 = BookFactory.create(book_category=category)
こういうときは、excludeとlazy_attributeを組み合わせて、factory側でマスターデータを取得すると便利。
class BookFactory(DjangoModelFactory): class Meta: model = models.Book exclude = ["category_name"] name = "Test Name" # Bookのmodelに存在しない、カテゴリを取得するキーとして使うだけのフィールド category_name = "comic" book_category = factory.LazyAttribute(lambda o: BookCategory.objects.get(name=o.category_name))
category_nameというフィールドを追加し、BookCategoryを検索するキーとして使用している。
book_categoryはLazyAttributeとして遅延評価させて取得している。
category_nameはBookには存在しないフィールドなので、excludeにに指定する必要がある。
(excludeに指定することで、factory内で使うだけのフィールドだということを明示している)
book2 = BookFactory.create(category_name='history')
Bookの生成は以上のようになるため、スッキリ書けるようになった。