Django

Django OneToOneField로 연결된 model 자동 생성

친구들안녕 2021. 6. 14. 10:35

서론

공부 삼아 만들던 중 기억하기 위해 쓰는 글입니다.

필자가 만들던 코드를 그대로 가져오므로 예시가 좀 이상할 수 있습니다.

 

본문

자동으로 생성해주는 코드는 django docs의 signals를 보면 된다

본문을 조금 떼어다 번역해보자면

다른 곳에서 작업이 발생할 때 알림을 받을 수 있도록 도와주는 signal dispather가 포함되어 있습니다.
Singerd을 통해 특정 sender는 어떤 조치가 취해졌음을 receiver에게 알릴 수 있습니다.

즉 singnal을 보내고, receiver로 받아서 그 뒤에 할 일을 정하는 것이다.

물론 이 글에서는 연결된 모델을 생성하는 걸 보여주겠다.

 

 

먼저 Video와 Post가 OneToOneField로 연결되어있는 상태를 보여주는 코드 예시이다.

여기서는 Video 생성 시 Post가 자동 생성되도록 만들겠다.

class Video(models.Model):
    author = models.ForeignKey(get_user_model(), on_delete=models.RESTRICT)
    video = models.FileField(upload_to='board/post/%Y/%m/%d/', validators=[
        FileExtensionValidator(allowed_extensions=['avi', 'mp4', 'mkv', 'mpeg', 'webm'])])
    ...

class Post(TimeModel):
    title = models.CharField(max_length=100)
    video = models.OneToOneField(Video, on_delete=models.CASCADE, related_name="post_video", unique=True)
    ...

 

여기서는 receiver 데코레이터를 사용하여 자동생성을 구현했다.

receiver로 post_save라는 signal을 받아 그 뒤에 할 일을 정하는데

post_save로 넘어온 Video 객체는 instance에 남아있다.

sender: signal 보내는 객체,

instance: signal을 보낸 객체에서 만들어진 object,

created: 만들어졌는지 여부의 boolean  

from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=Video)
def create_Post(sender, instance, created, **kwargs):
    name = os.path.basename(instance.video.name).split(".")[0]

    if created:
        if not hasattr(instance, 'Post'):
            Post.objects.create(video=instance, title=name)

그래서 created가 됐다면 hasattr로 Post객체에 instance가 들어있지 않는다면

Post.objects.create() 하여 Post object를 생성해주게 된다.

 

단 주의사항으로

blank=True나 default 같은 조건을 정하지 않았다면 빈 필드 때문에 에러가 발생할 수 있다.

 

참조

https://docs.djangoproject.com/en/3.2/ref/signals/#post-save

https://docs.djangoproject.com/en/3.2/ref/signals/

https://docs.djangoproject.com/ko/3.0/_modules/django/core/files/uploadedfile/

https://stackoverflow.com/questions/1652550/can-django-automatically-create-a-related-one-to-one-model