본문으로 바로가기

django-admin 커맨드를 만드는 방법은 다음 포스트를 참고하자

 

custom django-admin commands

우리는 Django 서버를 돌리기 위 python manage.py runserver를 돌려왔다. 이제는 이러한 명령어를 직접 만들어보자. Writing custom django-admin commands | Django documentation | Django Django The web fram..

darrengwon.tistory.com

 

Brobin/django-seed

:seedling: Seed your Django database with fake data - Brobin/django-seed

github.com

 

 

간단하고 적은 수의 데이터를 만드는 경우 다음과 같이 manager(Queryset)을 통해 단순히 데이터를 만들어서 넣어줄 수도 있다.

이런 케이스도 꽤나 많아서 자주 사용하는 편이다.

from django.core.management.base import BaseCommand
from rooms import models as room_models

class Command(BaseCommand):

    help = 'this command make facilities'

    def handle(self, *args, **options):
        facilities = [
            "Private entrance",
            "Paid parking on premises",
            "Paid parking off premises",
            "Elevator",
            "Parking",
            "Gym",
        ]
        for f in facilities:
            room_models.Facility.objects.create(name=f)
        self.stdout.write(self.style.SUCCESS("Facility created!"))

 

 

그러나, 더미 유저를 50개 만든다고 가정한다면, 위의 방법은 그리 현명하지 못한 방법이다.

각 필드마다 다른 값을 수작업으로 입력해야 하기 때문이다.

 

이럴 때는 Django-Seed를 이용하는 것이 좋다. github 페이지의 활용을 가져와보면 다음과 같다. (config/setting의 INSTALLED_APP 설정 등은 생략 하였다)

 

 

django-seed는 우리가 만든 모델의 Field를 보고 자동으로 랜덤한 값을 넣는다. 예를 들어 TextFields에는 적당한 길이의 문자열을 넣습니다.

 

다음은 github README.md에 올라와 있는 예제 코드를 가져온 것입니다.

기본적으로 seed를 생성하는 메서드는 다음과 같습니다.

add_entity(모델, 갯수, {조건})
from django_seed import Seed
from myapp.models import Game, Player

# Seed의 인스턴스 만들기
seeder = Seed.seeder()

# 해당 인스턴스의 add_entity 메서드를 이용해 모델 더미 데이터 만들기
seeder.add_entity(Game, 5)
seeder.add_entity(Player, 10, {
    'score':    lambda x: random.randint(0,1000),
    'nickname': lambda x: seeder.faker.email(),
})

# 인스턴스의 execute() 메서드로 실행!
seeder.execute()

 

위의 예제 코드를 이용하여 seed를 만들어봅시다.

 

나의 경우 다음과 같이 활용하여 python manage.py [파일명.py]를 통해 더미 유저를 생성할 수 있도록 만들어 보았다. 특히, add_entity의 세번 째 인자로 특정한 조건의 필드를 가진 값만 생성할 수 있다는 점을 유의하자.

from django.core.management.base import BaseCommand
from users.models import User
from django_seed import Seed


class Command(BaseCommand):

    help = "This command generated users"

    def add_arguments(self, parser):
        parser.add_argument(
            "--number", default=1, help="How many do you want create User"
        )

    def handle(self, *args, **options):
        number = int(options.get("number"))
        seeder = Seed.seeder()
        seeder.add_entity(User, number, {"is_staff": False, "is_superuser": False,})
        seeder.execute()
        # 성공했다고 확인 메세지
        self.stdout.write(self.style.SUCCESS(f"{number} users created!"))

 

 

해당 조건에 맞는 유저만 생성된 것을 볼 수 있다. 그 외의 필드들은 가급적 Seed가 랜덤한 값으로 채워준다. 혹시나 특정한 값만으로 채워져 있으면 Model에 default값이 생성되어 있는 것이 아닌가 체크하자. 

 

그런데 만약, seed로 생성하고자 하는 정보에 FK나 MTM 관계가 설정된 필드가 있다면 어떻게 해야 할까?

해당 모델을 불러와서 random.choice를 하게 만들면 된다. 간단~

import random
from django.core.management.base import BaseCommand
from reviews import models as review_models
from users import models as user_models
from rooms import models as rooms_moels
from django_seed import Seed


class Command(BaseCommand):

    help = "This command generated reviews"

    def add_arguments(self, parser):
        parser.add_argument(
            "--number", default=1, type=int, help="How many do you want create room"
        )

    def handle(self, *args, **options):
        number = options.get("number")
        seeder = Seed.seeder()
        
        # 모든 유저를 가져옵니다.
        users = user_models.User.objects.all()
        
        # 모든 방을 가져옵니다.
        rooms = rooms_moels.Room.objects.all()
        
        seeder.add_entity(
            review_models.Reviews,
            number,
            {
                "accuracy": lambda x: random.randint(0, 5),
                "communication": lambda x: random.randint(0, 5),
                "cleanliness": lambda x: random.randint(0, 5),
                "location": lambda x: random.randint(0, 5),
                "check_in": lambda x: random.randint(0, 5),
                "value": lambda x: random.randint(0, 5),
                
                # user 이름으로 users 중 하나를 choice합니다.
                "user": lambda x: random.choice(users),
                
                # room 이름으로 rooms 중 하나를 choice합니다.
                "room": lambda x: random.choice(rooms),
            },
        )
        seeder.execute()

        # 성공했다고 확인 메세지
        self.stdout.write(self.style.SUCCESS(f"{number} reviews created!"))

 

 

추가로, seeder.execute() 는 고유한 pk를 2차원 배열로 반환하므로 flatten하여(django의 메서드입니다.) 생성한 더미 데이터 각각에 새로운 값을 추가해주거나 기존 값을 수정할 해줄 수도 있다.

 

import random
from django.core.management.base import BaseCommand
from django.contrib.admin.utils import flatten
from reviews import models as review_models
from users import models as user_models
from rooms import models as rooms_models
from lists import models as lists_models
from django_seed import Seed


class Command(BaseCommand):

    help = "This command generated lists"

    def add_arguments(self, parser):
        parser.add_argument(
            "--number", default=1, type=int, help="How many do you want create lists"
        )

    def handle(self, *args, **options):
        number = options.get("number")
        seeder = Seed.seeder()
        users = user_models.User.objects.all()
        rooms = rooms_models.Room.objects.all()
        seeder.add_entity(
            lists_models.List,
            number,
            {
                # user 이름으로 users 중 하나를 choice합니다.
                "user": lambda x: random.choice(users),
            },
        )
        created = seeder.execute()
        cleaned = flatten(list(created.values()))

        for pk in cleaned:
            list_model = lists_models.List.objects.get(pk=pk)
            to_add = rooms[random.randint(0, 5) : random.randint(6, 30)]
            list_model.rooms.add(*to_add)

        # 성공했다고 확인 메세지
        self.stdout.write(self.style.SUCCESS(f"{number} lists created!"))

 

 

또한, Django-seed는 faker 라이브러리를 바탕으로 만들어졌으므로 seeder.faker 를 통해 faker가 제공하는 메서드를 사용할 수 있습니다. 

seeder = Seed.seeder()

# address를 랜덤하게 생성합니다
seeder.faker.address()

 

 

 


darren, dev blog
블로그 이미지 DarrenKwonDev 님의 블로그
VISITOR 오늘 / 전체