[Django] One to One Field 연결 모델 동시 생성
프로젝트를 진행하면서 모델을 설계했는데 일대일 관계에 있는 모델을 생성해야했다. 처음 설계 시에는 별다른 생각없이 그냥 설계를 했는데, API를 테스트하면서 부모 모델이 생성되면 자식 모델도 default로 같이 생성되는 형태의 로직이 필요했다 -> 아니 필수적이였다.
예를 들어 User하나에는 반드시 Allergy 모델이 있어야 한다고 하자.
User 하나가 생성되면 -> Allergy 모델도 default로 생성이 되어야한다.
일대일 대응 모델을 자동으로 생성해주는 코드는 Django docs의 signals를 보면 알 수 있다.
signal을 통해 특정 sender는 어떤한 행동이 취해졌음을 receiver에게 알릴 수 있다.
프로세스에서 signal을 전달하여 신호를 주고받는 느낌? 과 비슷한 맥락인 것 같다.
즉 signal을 이용하여 sender와 receiver가 신호를 주고 받는 개념을 이용하는 것이다.
User 모델과 Allergy모델을 각각 다음과 같이 정의한다.
# users.model
class User(AbstractUser):
name = models.CharField(max_length=255)
email = models.CharField(max_length=255, unique=True)
password = models.CharField(max_length=255)
gender = models.SmallIntegerField(choices=GENDER_CHOICES, null=True)
username = None
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
------------------------------------------------------------------------------------------
# allergy.model
class Allergy(models.Model):
egg = models.BooleanField(default=False) # 1. 난류
milk = models.BooleanField(default=False) # 2. 우유
buckwheat = models.BooleanField(default=False) # 3. 메밀
peanut = models.BooleanField(default=False) # 4. 땅콩
bean = models.BooleanField(default=False) # 5. 대두
wheat = models.BooleanField(default=False) # 6. 밀
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="allergy")
여기서 장고에서 제공하는 @receiver 라는 데코레이터를 사용하여 자동 생성을 구현할 수 있다.
@receiver(post_save, sender=User)
def create_Allergy(sender, instance, created, **kwargs):
if created:
Allergy.objects.create(user=instance)
# print('allergy model created success')
@receiver의 첫 번째 인자인 post_save는 signal의 한 종류로 연결된 객체가 저장(save)되었을 때 신호를 받는다. 신호의 종류는 장고에서 제공하는 signals.py를 들어가보면 더 자세히 알 수 있다. 신호를 보내는 객체는 두 번째 인자인 sender=User로 정의할 수 있다.
create_Allergy 함수의 인자들을 설명해보면 post_save로 넘어온 User 객체는 instance에 남아있다.
- sender: signal 보내는 객체 (User)
- instance: signal을 보낸 객체에서 만들어진 object (User user1)
- created: 객체가 생성되었는지를 알려주는 boolean 값
위 인자들을 이용하여 유저 객체가 생성되었을 때 해당 유저와 관련된 알러지 객체를 자동으로 생성하는 로직을 구현할 수 있다.