Published on

FactoryBoy 와 Faker를 이용한 더미데이터 기록하기

Authors

개발/프로젝트를 진행할 때마다 테스트용의 데이터는 필수입니다. 간혹 모델(테이블) 하나의 규모가 커질 때가 있는데, 만약 매번 데이터를 수작업으로 생성한다면 이는 엄청난 노동이 아닐 수 없습니다. 그렇기 때문에, 당연히 더미데이터를 만드는데 코드를 사용하는 것이 권장됩니다.

Python 에서 더미데이터를 생성하는데 유용한 라이브러리로 factory_boyFaker 가 있습니다. 굉장히 유연하고 추상화가 잘되어있지만, 그와 동시에 "어떤 provider 가 있었는지?" 매번 문서를 찾아봐야하는 불편함을 줄이고자 기록합니다.

핵심 = Provider 종류 Notes

1. Factory Boy와 Faker

factory_boyFaker는 각각 다른 라이브러리로써 두 라이브러리를 결합하면 강력하고 유연한 더미 데이터 생성 도우미(?)가 됩니다.

  • factory_boy는 Python 객체의 팩토리를 쉽게 생성할 수 있도록 돕는 라이브러리입니다.
    • Django 모델과 같은 ORM 객체를 포함하여 다양한 객체를 생성할 수 있습니다.
  • Faker는 다양한 언어와 locale 에 맞춘 현실적인 더미 데이터를 생성하는 라이브러리입니다.

1.1 설치하기

먼저, factory_boyFaker를 설치해야 합니다. 다음 명령어를 사용하여 설치할 수 있습니다.

pip install factory_boy faker

1.2 기본 사용 예

Factory Boy는 Django 모델 및 기타 Python 객체를 생성하는 데 사용되는 라이브러리입니다. 주요 기능은 다음과 같습니다.

  1. 객체 팩토리 정의

    • Factory Boy를 사용하면 Python 클래스로 객체 팩토리를 정의할 수 있습니다.

    • 팩토리 클래스에서 객체의 필드와 관계를 설정할 수 있습니다.

    • 예를 들어, Django User 모델의 팩토리 클래스를 다음과 같이 작성할 수 있습니다.

      import factory
      from django.contrib.auth.models import User
      
      class UserFactory(factory.django.DjangoModelFactory):
          class Meta:
              model = User
      
          username = factory.Faker('user_name')
          email = factory.Faker('email')
          password = factory.PostGenerationMethodCall('set_password', 'password123')
      
      
  2. 객체 생성

    • 정의한 팩토리 클래스를 통해 객체를 손쉽게 생성할 수 있습니다.
    • 예를 들어, UserFactory.create()를 호출하면 User 모델 객체가 생성됩니다.
    • 필요에 따라 객체의 필드 값을 직접 설정할 수도 있습니다.
  3. 관계 처리

    • 팩토리 클래스에서 다대다, 일대다 관계 등을 정의할 수 있습니다.
    • 관계가 있는 다른 객체도 자동으로 생성됩니다.
  4. Faker와의 결합

    • Factory Boy는 Faker 라이브러리와 잘 통합되어 사용할 수 있습니다.
    • Faker의 다양한 Provider를 활용하여 객체의 필드 값을 현실적으로 생성할 수 있습니다.

간단한 Django 모델인 User 모델을 사용하여 factory_boyFaker의 기본 사용 방법을 예시로 설명했습니다.

1.3 실 사용 예

아래에서 문자나 암호화되어지는 것 처럼 보여지는 부분에 bothify 라는 것을 응용했는데, 구현하기 귀찮은 부분에 꽤나 유용하게 사용할 수 있을 것 같습니다.

비교적 많은 필드의 Django 모델에서 아래처럼 사용해서 꽤나? 그럴싸한 데이터를 만들 수 있었습니다.


class ConstructionFactory(DjangoModelFactory):
    class Meta:
        model = Construction

    title = factory.Faker("company", locale="ko_KR")
    code = factory.Faker("bothify", text="????-########")
    start_at = factory.Faker("date_between", start_date="-1y", end_date="today")
    finish_at = factory.Faker("date_between", start_date="today", end_date="+1y")
    post_address = factory.Faker("postcode", locale="ko_KR")
    address = factory.Faker("address", locale="ko_KR")
    address_detail = factory.LazyFunction(lambda: f"{random.randint(1, 100)}호")
    cost = factory.LazyFunction(lambda: round(random.uniform(1000000, 1000000000), 2))

    client_company_name = factory.Faker("company", locale="ko_KR")
    client_owner_name = factory.Faker("name", locale="ko_KR")
    client_post_address = factory.Faker("postcode", locale="ko_KR")
    client_address = factory.Faker("address", locale="ko_KR")
    client_address_detail = factory.LazyFunction(lambda: f"{random.randint(1, 100)}호")

    designer_company_name = factory.Faker("company", locale="ko_KR")
    designer_owner_name = factory.Faker("name", locale="ko_KR")
    designer_post_address = factory.Faker("postcode", locale="ko_KR")
    designer_address = factory.Faker("address", locale="ko_KR")
    designer_address_detail = factory.LazyFunction(lambda: f"{random.randint(1, 100)}호")

    constructor_company_name = factory.Faker("company", locale="ko_KR")
    constructor_owner_name = factory.Faker("name", locale="ko_KR")
    constructor_post_address = factory.Faker("postcode", locale="ko_KR")
    constructor_address = factory.Faker("address", locale="ko_KR")
    constructor_address_detail = factory.LazyFunction(lambda: f"{random.randint(1, 100)}호")
    constructor_business_registration = factory.django.FileField(filename="business_registration.pdf")
    constructor_seal_img = factory.django.ImageField(color="blue")

    sub_constructor_company_name = factory.Faker("company", locale="ko_KR")
    sub_constructor_owner_name = factory.Faker("name", locale="ko_KR")
    sub_constructor_post_address = factory.Faker("postcode", locale="ko_KR")
    sub_constructor_address = factory.Faker("address", locale="ko_KR")
    sub_constructor_address_detail = factory.LazyFunction(lambda: f"{random.randint(1, 100)}호")
    sub_constructor_contract = factory.django.FileField(filename="subcontractor_contract.pdf")

결과적으로 company 와 같은 부분이 꽤나 그럴듯해서 만족스러웠습니다.

factoryboy_faker

1.4 ForeignKey 고려한 예시

더미데이터를 만들면서 ForeignKey를 몇몇의 특정 데이터를 고려하거나, 완전 랜덤하게 사용하고 싶은 경우도 많습니다.

그럴 때는 간단하게 factory 의 Iterator 객체를 사용하면, 부모모델의 데이터를 랜덤으로 가져옵니다.


    fk_field = factory.Iterator(SomeParentModel.objects.all())  # 원한다면 특정 몇몇의 데이터를 필터링해서 조절할 수도 있겠습니다.


2. Provider 종류 Notes

이번 글의 핵심인 부분입니다. 주요 Provider와 그 사용 예시를 정리했습니다.

이름 (Name) Provider

# 이름 생성
print(fake.name())# 예: 김민수

주소 (Address) Provider

# 주소 생성
print(fake.address())# 예: 서울특별시 강남구 테헤란로 123

회사 (Company) Provider


# 회사 이름 생성
print(fake.company())# 예: 삼성전자 주식회사

날짜와 시간 (Date and Time) Provider


# 과거 날짜 생성
print(fake.past_date())# 예: 2022-02-17# 미래 날짜 생성
print(fake.future_date())# 예: 2023-12-01

금융 (Finance) Provider


# 신용카드 번호 생성
print(fake.credit_card_number())# 예: 1234-5678-9876-5432

인터넷 (Internet) Provider


# 이메일 생성
print(fake.email())# 예: john.doe@example.com# URL 생성
print(fake.url())# 예: <http://www.example.com>

전화번호 (Phone Number) Provider


# 전화번호 생성
print(fake.phone_number())# 예: 010-1234-5678
print(fake.cell_phone())# 예: 010-1111-2222

색상 (Color) Provider


# 16진수 색상 코드 생성
print(fake.hex_color())# 예: #a6c4f1# RGB 색상 생성
print(fake.rgb_color())# 예: rgb(128,200,150)

이미지 (Image) Provider


# 이미지 URL 생성
print(fake.image_url())# 예: https://picsum.photos/seed/picsum/640/480# 이미지 데이터 생성 (PIL Image 객체)
image = fake.image(size=(640, 480))

지역 및 국가 (Geo) Provider


# 위도, 경도 생성
print(fake.latitude())# 예: 37.123456
print(fake.longitude())# 예: 127.654321# 주소 생성 (국가, 주, 도시 등)
print(fake.address())# 예: 123 Main Street, Springfield, CA 12345

우편번호 (Barcode) Provider


# 바코드 생성
print(fake.ean13())# 예: 4005537186013
print(fake.ean8())# 예: 11345976

기업 및 조직 (Company) Provider


# 기업 이름 생성
print(fake.company())# 예: 삼성전자 주식회사# 기업 접미사 생성
print(fake.company_suffix())# 예: 공업사

신용카드 (Credit Card) Provider


# 신용카드 정보 생성
print(fake.credit_card_full())# 예: VISA 4111111111111111 12/25 111
print(fake.credit_card_provider())# 예: VISA

문자조합 (bothify) Provider

# 8-12자리 영문 대소문자, 숫자, 특수문자로 구성된 비밀번호 생성
password = fake.bothify(text='?#?#?#?#!', letters='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
print(password)  # 예: Ht42Bq!9Xz

Custom Provider

Faker 라이브러리에서 사용자 정의 Provider를 추가하여 커스텀 데이터를 생성할 수 있습니다.


from faker.providers import BaseProvider

class MyCustomProvider(BaseProvider):
    def my_custom_field(self):
        return 'Custom Value'

fake.add_provider(MyCustom)

# 커스텀 필드 사용
print(fake.my_custom_field())# 예: Custom Value

3. 실행

from some_app.some_structure import SomeFactory


something = SomeFactory(data=data)

4. 참고 문서 링크

hongreat 블로그의 글을 봐주셔서 감사합니다!