이지미 파일 어떻게 불러왔는지 먼저 본다.
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이였지만 이제는 어떻게 흘러가는지 조금 알 것 같다 일단 시리얼라이저를 만지면서 벨리데이션 자체가 정형화된게 아니라 결국 사람이 만들고 코드를 적은대로 흘러간다는 걸 알았다 뭔가 맞춰진 것에 딱맞춰서 커스텀 하기 어렵다고 생각했지만 결국 내가 원하는 데이터 형식인지 알 수 있는 도구 였다.
여기서 정답이 없다는걸 느꼈고 최대한 클린한 코드를 만드는게 중요하다고 생각했다.
공부 기록용 데이터 찍어본것
시리얼라이저에서 함수 만들면 두개의 데이터(파라미터)가 들어온다 그걸 사용해줘야 작동한다 그래서 return data 해줬는데 정답인지는 모르겠다. 객체저장하고 db저장도 어떻게했는지 봤고 장고 공식문서 git 을 보고 도움도 많이 받았다.
validate 와 create 합쳐도 된다고 생각한다 팀원들과 이야기 해봐야겠다.
'Programming > 기술 실험, 공부' 카테고리의 다른 글
Django Channels | 개념 | 사용이유 (0) | 2022.12.23 |
---|---|
XSS | 백엔드 | 시리얼라이저에서 XSS 막아보기 (0) | 2022.12.22 |
select_related | prefetch_related | 쿼리줄이기 | 코드 리팩토링 | 공부 (0) | 2022.12.16 |
Validation 1편 : 어떻게 사용할까? (0) | 2022.11.30 |
JS 시작 (0) | 2022.11.18 |