한 번의 요청으로 테이블에 대량의 레코드를 삽입하고 싶을 때, 아래처럼 for문을 이용할 수 있다.
users = User.objects.all()
for user in users:
Notification(user=user, contents="반갑습니다.").save()
근데 이러면 save()
를 부를 때마다 DB와 커넥션이 발생해서 서비스에 큰 부하를 일으킬 수 있다. 이때 쓰는 것이 bulk_operation으로, 한 번의 커넥션만으로 다수의 레코드를 생성하고 업데이트할 수 있다. 사용법은 만들고자 하는 테이블 모델의 오브젝트 리스트를 만들어서 bulk_create
의 인자로 넘겨주면 된다.
users = User.objects.all()
new_noti_list = [Notification(user=user, contents="반갑습니다.") for user in users]
Notification.objects.bulk_create(new_noti_list)
for문으로 오브젝트들을 하나씩 건드리는건 똑같지만 디비에는 한번의 커넥션만으로 삽입이 가능하다는 점에서 다르다.
image_strings = self.context.get("images")
decoded = []
for image_string in image_strings:
decoded.append(base64.b64decode(image_string))
num = 1
for img in decoded:
filename = f'{img}'
media_root = settings.MEDIA_ROOT + '\\' + "filename"+str(num)+".png"
with open(media_root, 'wb') as f:
f.write(img)
ProductImg.objects.create(
image = f'/filename{num}.png',
product=product
)
num += 1
bulk_list = []
num = 1
for image_string in self.context.get("images"):
image_data = base64.b64decode(image_string) # 이미지 디코딩
image_root = settings.MEDIA_ROOT + '\\' + str(num) + ".png" # 이미지 파일 경로
with open(image_root, 'wb') as f:
f.write(image_data) # 이미지 파일 생성
bulk_list.append(ProductImg(product=product, image=f'{num}.png'))
num += 1
images = ProductImg.objects.bulk_create(bulk_list)
기존코드에서는 디코딩하느라 for문 한번 돌고, 이미지 파일 만들어서 디비에 저장하느라 for문 한번 돌고, 또 두번째 for문에서는 매번 objects.create()
를 통해 디비에 접근해서 이미지 객체를 등록했다. bulk_create()
를 사용해서 바꾼 현재 코드에서는 일단 for문을 한번밖에 돌지 않는다. 불필요한 부분은 다 빼고 한큐에 해결하는 쪽으로 코드를 수정했다. for문을 한번 돌면서 디코딩한 값을 image_data
에 저장하고, image_root
에 그 이미지 파일 경로를 넣은 다음, 그 파일을 열어서 image_data
를 그대로 써주고 bulk_list
에 ProductImg
객체를 추가한다. 이때 create
를 사용하지는 않았기 때문에 아직 디비에는 한번도 접근하지 않은 것이다. 이제 반복문을 나와서 bulk_create
를 통해 bulk_list
에 있는 이미지 객체들을 한방에 디비에 등록해준다.
테스트 결과 bulk_create
로도 다음과 같이 디비에 잘 저장이 됐다.