본문으로 바로가기

이지미 파일 어떻게 불러왔는지 먼저 본다.

    def create(self, validated_data):
        print("validated_data",validated_data)
        instance = super().create(validated_data)
        image_set = self.context['request'].FILES.getlist('images')
        print("instance",instance)
        print("images_set",image_set)
        image_list = [GoodsImage(goods = instance, image = image) for image in image_set]
        print("image_list",image_list)

        GoodsImage.objects.bulk_create(image_list)
        return instance

현재코드 이미 valid 된 데이터를 바로 저장 post할떄는 현재 이미지의 serilizer 거치지 않음

저장하는 데이터에 밸리데이션 걸어도 될 것 같고 시리얼라이저 적용된 이중 시리얼 라이저로 시도해보자

1. 모델에서 우선적으로 막아보기 # 밸리데이터 사용해도 저장이 되네..

2. 시리얼라이저에 시리얼라이저 사용

3. 밸리데이션  # 밸리데이션으로 간단하게 유효성 검사가 가능했다.

validated_data {'title': 'ㅅㅅㅅㅅㅅㅅ', 'content': '123', 'category': '디지털기기', 'predict_price': 123, 'start_price': 123, 'start_date': datetime.date(2022, 12, 17), 'start_time': '13:50', 'seller_id': 1}
instance Goods object (31)
images_set [<InMemoryUploadedFile: disappointment.png (image/png)>]
images_set [<GoodsImage: GoodsImage object (None)>]

1. 데코레이터로 함수에 데코레이터 붙여주기

현재 코드상황에 맞지 않다고 판단 사진과 data 함께 저장

def my_decorator(input):
    def wrapper(func):
        @wraps(func)
        def decorator(request, *args, **kwargs):
            #
            # DO SOMETHING HERE
            #
            return func(request, *args, **kwargs) # 데코레이팅(?)된 함수 실행
        return decorator
    return wrapper
def limit_file_size(max_size): # 여기에서 입력값을 받을 수 있음. max_size
    def wrapper(func):
        @wraps(func)
        def decorator(request, *args, **kwargs):
            print(request.data)
            files = request.self.context['request'].FILES.getlist('images')

            for k in files.keys():
                if files[k].size > max_size: # 여기에서 입력값 max_size 사용
                    return "error"
            return func(request, *args, **kwargs) # 데코레이팅(?)된 함수 실행
        return decorator
    return wrapper

2. 모델에 밸리데이터 적용

밸리데이터를 별도로 만들어서 모델에 넣어주는 방식을 생각해봤지만 적용을 하지못함 일단 db 에 저장되는 글을 보았음

class GoodsImage(models.Model): goods = models.ForeignKey(Goods, on_delete=models.CASCADE) image = models.ImageField(upload_to='goods/',validators=[validate_image_file_extension, logo_validator])
from rest_framework.exceptions import ValidationError
from django.core.files.images import get_image_dimensions

MEGABYTE_LIMIT = 1
REQUIRED_WIDTH = 1
REQUIRED_HEIGHT = 1

def logo_validator(image):
    filesize = image.size
    print("filesize",filesize)

    width, height = get_image_dimensions(image)
    print("filesize",width, height)
    if width != REQUIRED_WIDTH or height != REQUIRED_HEIGHT:
        print("여기 왔어요")

        raise ValidationError(f"You need to upload an image with {REQUIRED_WIDTH}x{REQUIRED_HEIGHT} dimensions")

    if filesize > MEGABYTE_LIMIT * 1 * 1:
        print("여기 왔어요")
        raise ValidationError(f"Max file size is {MEGABYTE_LIMIT}MB")

3. 사진과 내용을 한번에 저장하는 현재 코드에 적용하기위해 밸리데이터 작성해서 파일크기를 제한하기로 결정

    def create(self, validated_data):
        print("validated_data",validated_data)
        instance = super().create(validated_data)
        image_set = self.context['request'].FILES.getlist('images')
        print("instance",instance)
        print("images_set",image_set)
        image_list = [GoodsImage(goods = instance, image = image) for image in image_set]
        print("image_list",image_list)
        for image in image_set:
            seralizer=GoodsImageSerializer(image)
            print("seralizer",seralizer)
            if seralizer.is_valid():
                GoodsImage.objects.bulk_create(seralizer)
                continue
            return instance

이 메소드 하나에 시리얼라이저나 밸리데이터를 넣어서 오류를 뜨게 하고싶었다.

클린하지는 않지만 기능은 제대로하는 코드

    def validate(self, data):
    # 에러 메시지도 설정할 수 있다.
        image_set = self.context['request'].FILES.getlist('images')
        print(image_set[0].size)
        for i in image_set:
            if i.size>1:
                print("밸리데이터 데이터",image_set)
                raise serializers.ValidationError("Image size.")
        return data

    def create(self, validated_data):
        print("validated_data",validated_data)
        instance = super().create(validated_data)
        image_set = self.context['request'].FILES.getlist('images')
        print("instance",instance)
        print("images_set",image_set)
        image_list = [GoodsImage(goods = instance, image = image) for image in image_set]
        print("image_list",image_list)
        print("instance_size",image_set[0])
        print("instance_size",image_set[0].size)
        # print("instance_size",image_set[0].height)
        # print("instance_size",image_set[0].width)

        GoodsImage.objects.bulk_create(image_list)
        return instance
    def validate(self, data):
        # 바이트 기준
        file_size= 34000
        required_width = 1000
        required_height = 1000
        image_set = self.context['request'].FILES.getlist('images')
        print(image_set[0].size)
        for i in image_set:
            width, height = get_image_dimensions(i)
            print(get_image_dimensions(i))
            if i.size > file_size:
                print("밸리데이터 데이터",image_set)
                raise serializers.ValidationError("Image size.")
            elif width > required_width or height > required_height:
                raise serializers.ValidationError("Image size.")
            else:
                return data

사진 크기 용량 모두 고려한 밸리데이션 그리고 유지보수가 쉬운 구조

 

ps. 생소한 장고 시리얼구조와 viewset이였지만 이제는 어떻게 흘러가는지 조금 알 것 같다 일단 시리얼라이저를 만지면서 벨리데이션 자체가 정형화된게 아니라 결국 사람이 만들고 코드를 적은대로 흘러간다는 걸 알았다 뭔가 맞춰진 것에 딱맞춰서 커스텀 하기 어렵다고 생각했지만 결국 내가 원하는 데이터 형식인지 알 수 있는 도구 였다.

여기서 정답이 없다는걸 느꼈고 최대한 클린한 코드를 만드는게 중요하다고 생각했다. 

def validate(self, data):
# 바이트 기준
print(data)
file_size= 34000
required_width = 1000
required_height = 1000
image_set = self.context['request'].FILES.getlist('images')
print(image_set[0].size)
for i in image_set:
width, height = get_image_dimensions(i)
print(get_image_dimensions(i))
if i.size > file_size:
print("밸리데이터 데이터",image_set)
raise serializers.ValidationError("사진용량 초과")
elif width > required_width or height > required_height:
raise serializers.ValidationError("사진크기 초과")
return data

def create(self, validated_data):
print("validated_data",validated_data)
instance = super().create(validated_data)
image_set = self.context['request'].FILES.getlist('images')
print("instance",instance)
print("images_set",image_set)
image_list = [GoodsImage(goods = instance, image = image) for image in image_set]
print("image_list",image_list)
print("instance_size",image_set[0])
print("instance_size",image_set[0].size)
# print("instance_size",image_set[0].height)
# print("instance_size",image_set[0].width)

GoodsImage.objects.bulk_create(image_list)
return instance

공부 기록용 데이터 찍어본것

시리얼라이저에서 함수 만들면 두개의 데이터(파라미터)가 들어온다 그걸 사용해줘야 작동한다 그래서 return data 해줬는데 정답인지는 모르겠다. 객체저장하고 db저장도 어떻게했는지 봤고 장고 공식문서 git 을 보고 도움도 많이 받았다.

validate 와 create 합쳐도 된다고 생각한다 팀원들과 이야기 해봐야겠다.