Lors de la création d'un système de gestion d'applications Web, je rencontre souvent le modèle «Je veux que vous puissiez télécharger les données système dans un fichier CSV qui peut être ouvert dans Excel». Si vous créez un CSV sans penser à quoi que ce soit dans Python3, ce sera un codage de caractères UTF-8, donc s'il s'agit du paramètre par défaut d'Excel, les caractères seront déformés. Bien sûr, si vous spécifiez correctement l'encodage de lecture dans Excel, vous pouvez l'ouvrir sans problème, mais on dit souvent que "je ne comprends pas ça, alors ne déformez pas depuis le début". Dans ce cas, il est nécessaire de créer un fichier CSV avec l'encodage pour Windows (CP932, ou Shift_JIS, SJIS).
Cette fois, j'utilisais Chalice, mais après avoir regardé attentivement le document, je suis resté coincé, alors j'ai pris une note.
$ pipenv run chalice --version
chalice 1.21.2, python 3.8.2, linux 5.4.0-52-generic
Cette fois, je veux le renvoyer avec Response, j'ai donc pensé que ce serait possible si je mettais une valeur appropriée dans le corps de la classe Response. Cependant, le document au moment de la rédaction de l'article (23 octobre 2020) indique:
class Response(body, headers=None, status_code=200) body: The HTTP response body to send back. This value must be a string.
Cité et extrait de https://aws.github.io/chalice/api.html#response. Partiellement souligné.
Penser en lisant ceci.
"Eh ...? La chaîne de caractères encodée en CP932 est de type octets, donc je ne peux pas la passer ici ...? Si ce n'est pas possible, créez un fichier, téléchargez-le sur S3 et faites-le télécharger ..."
Cependant, même si vous mettez des octets dans ** body, il passera **. Il semble que la «chaîne» dans ce document soit destinée à une chaîne plus large que le «type str». Quand j'ai cherché à nouveau, Une personne avec la même question m'a posé une question.
Vous pouvez également passer le ** type d'octets ** au Response # body
** de Chalice. Si vous l'implémentez en fonction de cela, cela ressemblera à ceci. Si vous accédez à /
avec un navigateur, il sera téléchargé sous forme de fichier CSV.
app.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
import csv
import tempfile
from chalice import Chalice, Response
app = Chalice(app_name='csvtest')
def csv_response(filename, encoding='utf8'):
"""Comment renvoyer un fichier CSV 1:Réponse directe"""
with tempfile.TemporaryFile(mode='r+', encoding=encoding) as fh:
#Ecrire avec l'écrivain
writer = csv.writer(fh, lineterminator='\r\n')
writer.writerow(['Nom d'utilisateur', 'Date et heure de connexion'])
writer.writerow(['user01', '2000/01/01 00:00:00'])
#Lire toutes les données écrites en données
fh.seek(0)
data = fh.read()
headers = {}
headers['Content-Type'] = 'text/csv'
headers['Content-Disposition'] = f'attachment;filename="{filename}"'
return Response(body=data, status_code=200, headers=headers)
@app.route('/')
def index():
return csv_response('test.csv', encoding='cp932')
Dans l'exemple précédent, «tmpfile» est utilisé pour créer un fichier en mémoire, puis «data» est lu. Cependant, dans le cas d'AWS Lambda, il est exécuté dans un environnement où l'utilisation de la mémoire est limitée, on peut donc imaginer que l'utilisation de la mémoire sera considérablement affectée lorsque le fichier devient volumineux. Bien sûr, c'est un problème qui peut être évité en augmentant la limite supérieure d'utilisation de la mémoire, mais si la charge double, vous pouvez hésiter.
Dans ce cas, vous pouvez créer temporairement un fichier sous / tmp
fourni par AWS Lambda et télécharger le fichier créé sur S3.
Après le téléchargement sur S3, vous pouvez accéder au fichier créé via la communication de CloudFront --S3
, ou créer et fournir une URL temporaire pour permettre à l'utilisateur de le télécharger.
Notez que «TempfileContext» n'est pas l'essence du code car il est préparé pour que les fichiers sous «/ tmp» utilisés dans AWS Lambda puissent être supprimés sans tenir compte de la gestion des erreurs.
import os
import csv
import uuid
import boto3
s3 = boto3.client('s3')
class TempfileContext:
"""Fournit un contexte pour créer et supprimer des fichiers temporaires"""
def __init__(self):
tmpfile = str(uuid.uuid4())
self.filename = f'/tmp/{tmpfile}'
def __enter__(self):
return self
def __exit__(self, ex_type, ex_value, trace):
try:
if os.path.exists(self.filename):
os.remove(self.filename)
except Exception:
pass
def create_and_upload_csv(filename, encoding='utf8'):
"""Comment renvoyer un fichier CSV 2:Créez un CSV et téléchargez-le sur S3"""
with TempfileContext() as tmp:
# 1. /Créez un fichier CSV dans la zone tmp
with open(tmp.filename, 'w', encoding=encoding) as fh:
#Ecrire avec l'écrivain
writer = csv.writer(fh, lineterminator='\n')
writer.writerow(['Nom d'utilisateur', 'Date et heure de connexion'])
writer.writerow(['user01', '2000/01/01 00:00:00'])
# 2.Télécharger vers S3
s3.upload_file(tmp.filename, BUCKETNAME, f'uploads/{filename}')
Recommended Posts