본문 바로가기

DRF

Django csv파일 다운로드

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