Django Export csv(zip, base64)
django에서 csv 파일로 내보내기
django에서 db에 저장되어 있는 값들을 csv로 변환해서 다운로드 할 수 있도록 하는 것을 목표로 한다.
Molecular 테이블에 model_output 필드에는 문자열이 저장되어 있다.
# views.py
def get(self, request, *args, **kwargs):
files_name = Molecular.objects.filter(id=1).first().model_output["simul_plus"].keys()
files_name_s = Molecular.objects.filter(id=1).first().model_output["custom_model"].keys()
field_name = ("id", "smiles", *files_name, *files_name_s)
field_name 에는 키 값들이 들어가도록 하였다. 이 변수는 나중에 csv로 변환할 때 인자로 필드들을 받을 때 쓰인다.
단순히 하나의 파일만 csv파일로 변환하는것이 아닌 다중 파일을 선택받아서 여러개의 파일들을 csv 파일로 변환시켜주어야 했다.
# views.py
molecular = molecular_list.split(",")
data_list = []
for i in molecular:
output_list = Molecular.objects.filter(id=i).values("id", "smiles", "model_output")
first_list = dict(id=output_list[0]["id"])
second_list = dict(smiles=output_list[0]["smiles"])
third_list = output_list[0]["model_output"]["simul_plus"]
fourth_list = output_list[0]["model_output"]["custom_model"]
pre_list = {**first_list, **second_list, **third_list, **fourth_list}
data_list.append(pre_list)
outpit_list 에 Molecular 테이블의 필드값들을 넣어 준다. output_list 에 값들이 각각의 딕셔너리로 들어가게 되어서 모든 값들을 넣어주기 위해 별도의 과정을 거쳤다.
# views.py
import csv
csv_file = open(f"test.csv", "w")
wr = csv.DictWriter(csv_file, fieldnames=field_name)
wr.writeheader()
for data in data_list:
wr.writerow(data)
csv_file.close()
open 함수를 이용하여 csv 파일을 만든 뒤 csv 라이브러리를 사용하여 csv 파일로 만들어준다. csv 라이브러리를 이용하면 쉽게 변환이 가능하다.
csv 파일을 zip 파일로 다시 변환해준다.
# views.py
import zipfile
from django.http import HttpResponse
zip_file = zipfile.ZipFile("molecular.zip", "w")
zip_file.write(f"test.csv")
zip_file.close()
# Return zip
response = HttpResponse(open("molecular.zip", "rb"), content_type="application/zip")
response["Content-Type"] = "application/x-zip-compressed"
response["Content-Disposition"] = "attachment; filename=molecular.zip"
return response
zipfile 라이브러리를 사용하여 빈 zip 파일을 만든 뒤 위에서 만든 csv 파일을 빈 zip파일에 넣어준다.
HttpResponse를 사용하여 response에 zip 파일이 응답가능하도록 변환시켜준다.
swagger에서 확인해보면 zip 파일 다운로드 버튼이 생긴것을 확인할 수 있다.
하지만 프론트에서 해당 api 를 조회했을 때 해당 파일의 문자열이 반환되는 것을 발견했다. 결국 base64형태로 변환해서 보내주면 프론트에서 base64를 파일로 변환해주는 라이브러리를 사용하도록 결정하였다.
다음은 base64 형태로 변환하여 응답해주는 코드이다.
# views.py
import csv
import zipfile
from django.http import HttpResponse
def get(self, request, *args, **kwargs):
files_name = Molecular.objects.filter(id=1).first().model_output["simul_plus"].keys()
files_name_s = Molecular.objects.filter(id=1).first().model_output["custom_model"].keys()
field_name = ("id", "smiles", *files_name, *files_name_s)
molecular = molecular_list.split(",")
data_list = []
for i in molecular:
output_list = Molecular.objects.filter(id=i).values("id", "smiles", "model_output")
first_list = dict(id=output_list[0]["id"])
second_list = dict(smiles=output_list[0]["smiles"])
third_list = output_list[0]["model_output"]["simul_plus"]
fourth_list = output_list[0]["model_output"]["custom_model"]
pre_list = {**first_list, **second_list, **third_list, **fourth_list}
data_list.append(pre_list)
csv_file = open(f"test.csv", "w")
wr = csv.DictWriter(csv_file, fieldnames=field_name)
wr.writeheader()
for data in data_list:
wr.writerow(data)
csv_file.close()
zip_file = zipfile.ZipFile("molecular.zip", "w")
zip_file.write(f"test.csv")
zip_file.close()
# Return zip
response = HttpResponse(open("molecular.zip", "rb"), content_type="application/zip")
response["Content-Type"] = "application/x-zip-compressed"
response["Content-Disposition"] = "attachment; filename=molecular.zip"
res_byte = response.content
res_base64 = base64.b64encode(res_byte)
res_base64_str = res_base64.decode("ascii")
return Response(res_base64_str)
csv 파일 다운로드 공식 문서(https://docs.djangoproject.com/en/4.1/howto/outputting-csv/)
'DRF' 카테고리의 다른 글
Django full text search (Gin index) (0) | 2022.12.09 |
---|