Django 다중 이미지

Han07·2021년 3월 30일
2
post-thumbnail

지난 포스트에서 이미지를 처리해 보았다. 간단히 정리해 보자면

  1. 모델에 이미지 필드 선언
  2. 시리얼라이저에 이미지 선언

이렇게 된다. 하지만 이미지 여러개를 처리해야 한다면 어떻게 될까?
예를 들어 SNS를 개발할 때 이미지 2개를 넣어야 한다고 생각해보자. 코드는 대략 이렇게 될 것이다.

models.py

image_1 = models.ImageField(default='media/user/default_image.jpeg')
image_2 = models.ImageField(default='media/user/default_image.jpeg')

serializers.py

image_1 = serializers.ImageField(use_url=True)
image_2 = serializers.ImageField(use_url=True)

음...🤔

좋다. 이번에는 인스타그램과 같은 SNS를 개발할 것이다. 한 포스트에 이미지 10개를 넣을 수 있다. 코드를 봐보자.

models.py

image_1 = models.ImageField(default='media/user/default_image.jpeg')
image_2 = models.ImageField(default='media/user/default_image.jpeg')
image_3 = models.ImageField(default='media/user/default_image.jpeg')
image_4 = models.ImageField(default='media/user/default_image.jpeg')
image_5 = models.ImageField(default='media/user/default_image.jpeg')
image_6 = models.ImageField(default='media/user/default_image.jpeg')
image_7 = models.ImageField(default='media/user/default_image.jpeg')
image_8 = models.ImageField(default='media/user/default_image.jpeg')
image_9 = models.ImageField(default='media/user/default_image.jpeg')
image_10 = models.ImageField(default='media/user/default_image.jpeg')

serializers.py

image_1 = serializers.ImageField(use_url=True)
image_2 = serializers.ImageField(use_url=True)
image_3 = serializers.ImageField(use_url=True)
image_4 = serializers.ImageField(use_url=True)
image_5 = serializers.ImageField(use_url=True)
image_6 = serializers.ImageField(use_url=True)
image_7 = serializers.ImageField(use_url=True)
image_8 = serializers.ImageField(use_url=True)
image_9 = serializers.ImageField(use_url=True)
image_10 = serializers.ImageField(use_url=True)

좋다. 코드가 심하게 더럽기는 하지만 짤 수는 있다. 그럼 만약 이미지 개수가 100개라면? 머리가 아찔해진다.
우리에겐 다행히도, 이미지 여러개를 받기 위해서 이렇게 필드를 무지막지하게 선언할 필요는 없다.


지금까지 우리는 한 테이블에 다른 여러 컬럼에 이미지 컬럼을 만들었다. 이렇게 말이다.

하지만 이미지를 많이 받을 수록 컬럼 수가 늘어난다는 단점이 있다(이미지 10개 때문에 컬럼 10개가 늘어난다.)
그렇기 때문에 우리는 이미지 테이블을 따로 만들 것이다.

이런 식으로 말이다.

위 ERD를 보면 user테이블과 user_image테이블은 서로 1:N관계로 이어져 있다.


위 사항을 응용해보자.

우리가 구현할 DB이다. user는 구현되어 있다 하고 diary부터 개발해보겠다.

models.py

class Diary(models.Model):
    id = models.BigAutoField(primary_key=True)
    user = models.ForeignKey(User, related_name="diary_user", on_delete=models.CASCADE, null=True)
    title = models.CharField(max_length=30)
    content = models.CharField(max_length=200)


class DiaryImage(models.Model):
    diary = models.ForeignKey(Diary, on_delete=models.CASCADE)
    image = models.ImageField(default='media/diary/default_image.jpeg', upload_to='diary',
                              blank=True, null=True)

다이어리와 이미지 모델이다. 다이어리에 외래키로 user의 id를 지정해주고, 다이어리 이미지에는 외래키로 다이어리의 id를 지정해준다.

serializers.py

from rest_framework import serializers

from diary.models import DiaryImage, Diary


class DiaryImageSerializer(serializers.ModelSerializer):

    image = serializers.ImageField(use_url=True)

    class Meta:
        model = DiaryImage
        fields = ['image']


class DiarySerializer(serializers.ModelSerializer):

    images = DiaryImageSerializer(many=True, read_only=True)


    class Meta:
        model = Diary
        fields = ['id', 'title', 'content', 'date_created', 'images']
        
        
    def create(self, validated_data):
        instance = Diary.objects.create(**validated_data)
        image_set = self.context['request'].FILES
        for image_data in image_set.getlist('image'):
            DiaryImage.objects.create(diary=instance, image=image_data)
        return instance

짠. 완성이다! 이제 이미지를 여러 개 저장할 수 있다.

하지만 아직 해결하지 못한 것이 하나 있다. 나는 DiarySerializer를 통해 이미지까지 모두 보고싶다. 현재 다이어리 시리얼라이저를 이용해 viewset을 만들어보면

{
    "id": 15,
    "title": "title1",
    "content": "content1",
    "date_created": "2021-03-29"
}

이렇게 이미지가 나오지 않는다. viewset에서는 diary serializer만 이용하기 때문이다. 이것을 해결하기 위해 다이어리 시리얼라이저의 필드를 살짝 바꿔주겠다.

serializers.py

class DiarySerializer(serializers.ModelSerializer):
    images = serializers.SerializerMethodField()

    def get_images(self, obj):
        image = obj.diaryimage_set.all()
        return DiaryImageSerializer(instance=image, many=True).data

    class Meta:
        model = Diary
        fields = ['id', 'title', 'content', 'date_created', 'images']

    def create(self, validated_data):
        instance = Diary.objects.create(**validated_data)
        image_set = self.context['request'].FILES
        for image_data in image_set.getlist('image'):
            DiaryImage.objects.create(diary=instance, image=image_data)
        return instance

SerializerMethodField()를 이용해 시리얼라이저 필드를 커스텀 하였다.

{
    "id": 73,
    "title": "hello!",
    "content": "hello_content",
    "date_created": "2021-03-31",
    "images": [
        {
            "image": "http://localhost:8000/media/diary/DRF_Imagefield_1_tw1aZsT.png"
        },
        {
            "image": "http://localhost:8000/media/diary/django_test_x73GRWC.png"
        }
    ]
}

응답 값이다. 이렇게 다중 이미를 처리할 수 있다.

0개의 댓글