Django Rest Framework のテストでハマったこと (3)

Published: 2021-10-01 22:00 +0900 by Chirimen

factory_boy の Faker() で、 取得した値を加工してから使用する話。

Faker() で取得した値の加工

Faker(‘address’) で住所と建物名を取得する

Faker('address') で住所を取得すると、 '大阪府富津市細野33丁目16番13号 皇居外苑シャルム938' のように、 住所と建物名が空白で連結された文字列を取得できる (建物名が定義されない場合もある)。

class AddressFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = models.Address
    address = factory.Faker('address', locale='ja_JP')
    building = ''   # ← ここに建物名を設定したい
# address のインスタンスを取得
address = AddressFactory()
address.address     # '大阪府富津市細野33丁目16番13号 皇居外苑シャルム938' ← 建物名まで含まれる
address.building    # '' ← 設定していないので空文字列のまま

これを、 ‘大阪府富津市細野33丁目16番13号` と ‘皇居外苑シャルム938’ のように、 住所と建物名を分離したレコードとして設定したい。

Facker() の返す値は直接加工できない

気分としては address, building = factory.Faker('address').split() というような感じで設定したいのだけれども、 factory.Facker() が返すのは文字列ではないのでエラーになる。

    # factory.Facker() が返すのは文字列でないのでエラーになる
    address, building = factory.Faker('address', locale='ja_JP').split()

LazyAttribute() の利用

こういうときは LazyAttribute() を使用する。 引数に指定した lambda 関数に インスタンス化されたオブジェクトが渡されるので、 別の変数、例えば fulladdressFaker('address') を設定するようにしておいて、 LazyAttribute() で値を取り出して加工した結果を目的の変数に格納する。

    # 一旦別の変数で受けてから LazyAttr で加工する
    fulladdress = factory.Faker('address', locale='ja_JP')
    address = factory.LazyAttribute(lambda o: o.fulladdress.split()[0])
    building = factory.LazyAttribute(lambda o: (o.fulladdress.split() + [''])[1])

exclude で仮の変数を除外する

このままだと、 追加した fullladderssmodels.Address で定義されていない変数なのでエラーになってしまう。 除外するには、 クラス Metaexcludefulladdres を指定すればよい。

class AddressFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = models.Address
        exclude = ('fulladdress',)      # exclude で models.Address に含まれない変数を指定
    fulladdress = factory.Faker('address', locale='ja_JP')
    address = factory.LazyAttribute(lambda o: o.fulladdress.split()[0])
    building = factory.LazyAttribute(lambda o: (o.fulladdress.split() + [''])[1])

名前の取得例

同様にして、 名前とフリガナのペアを取得し、 それぞれを別の変数に格納できる。 そのようにすると、漢字と読みが対応したレコードを作成できる (個別に factory.Faker() で取得すると、漢字と読みの対応関係が崩れてしまう)。

class PersonFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = models.Person
        exclude = ('firstname_pair', 'lastname_pair')
    firstname_pair = factory.Faker('first_name_pair', locale='ja_JP')
    lastname_pair = factory.Faker('last_name_pair', locale='ja_JP')
    lastname = factory.LazyAttribute(lambda o: o:lastname_pair[0])
    lastname_kana = factory.LazyAttribute(lambda o: o:lastname_pair[1])
    firstname = factory.LazyAttribute(lambda o: o:firstname_pair[0])
    firstname_kana = factory.LazyAttribute(lambda o: o:firstname_pair[1])
person = PersonFactory()
person.firstname        # '康弘'
person.firstname_kana   # 'ヤスヒロ'
person.lastname         # '近藤'
person.lastname_kana    # 'コンドウ'

Share

Latest Posts

Django Rest Framework のテストでハマったこと (4)

Django で既存データベースから inspectdb で作成した models.my は managed = False となっている。 そのままだと test を実行したときに、 テスト用データベースにモデルに対応したテーブルが作成されない。

Django Rest Framework のテストでハマったこと (3)

factory_boy の Faker() で、 取得した値を加工してから使用する話。

Django Rest Framework のテストでハマったこと (2)

Django のテスト用データを作成するのによく用いられる factory_boy で locale を指定して日本語圏用のデータを利用する話。