Beim Erstellen eines Webanwendungsverwaltungssystems tritt häufig das Muster "Ich möchte, dass Sie Systemdaten in eine CSV-Datei herunterladen können, die in Excel geöffnet werden kann" auf. Wenn Sie eine CSV erstellen, ohne an Python3 zu denken, handelt es sich um eine UTF-8-Zeichencodierung. Wenn dies die Standardeinstellung von Excel ist, werden die Zeichen verstümmelt. Wenn Sie die Lesekodierung in Excel richtig angeben, können Sie sie natürlich problemlos öffnen, aber es wird oft gesagt, dass "ich das nicht verstehe, also nicht von Anfang an verstümmeln". In diesem Fall muss eine CSV-Datei mit der Codierung für Windows (CP932 oder Shift_JIS, SJIS) erstellt werden.
Diesmal habe ich Chalice verwendet, aber als ich mir das Dokument genau angesehen habe, bin ich festgefahren und habe mir eine Notiz gemacht.
$ pipenv run chalice --version
chalice 1.21.2, python 3.8.2, linux 5.4.0-52-generic
Dieses Mal möchte ich es mit Response zurückgeben, daher dachte ich, dass es möglich wäre, wenn ich einen geeigneten Wert in den Hauptteil der Response-Klasse einfügen würde. In dem Dokument zum Zeitpunkt des Schreibens des Artikels (23. Oktober 2020) heißt es jedoch:
class Response(body, headers=None, status_code=200) body: The HTTP response body to send back. This value must be a string.
Zitiert und Auszug aus https://aws.github.io/chalice/api.html#response. Teilweise betont.
Denken beim Lesen.
"Eh ...? Die in CP932 codierte Zeichenfolge ist ein Bytetyp, daher kann ich sie hier nicht übergeben ...? Wenn dies nicht möglich ist, erstellen Sie eine Datei, laden Sie sie in S3 hoch und lassen Sie sie herunterladen ..."
** body kann jedoch auch dann übergeben werden, wenn Bytes eingegeben werden **. Es scheint, dass der "String" in diesem Dokument für einen breiteren String als nur den "Str-Typ" gedacht ist. Als ich es noch einmal nachschlug, stellte mir eine Person mit derselben Frage eine Frage.
Sie können auch den Typ ** Bytes ** an Chalices Response # body
** übergeben. Wenn Sie es darauf basierend implementieren, sieht es so aus. Wenn Sie mit einem Browser auf /
zugreifen, wird es als CSV-Datei heruntergeladen.
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'):
"""So geben Sie eine CSV-Datei zurück 1:Direkte Antwort"""
with tempfile.TemporaryFile(mode='r+', encoding=encoding) as fh:
#Schreiben Sie mit dem Schriftsteller
writer = csv.writer(fh, lineterminator='\r\n')
writer.writerow(['Nutzername', 'Datum und Uhrzeit der Anmeldung'])
writer.writerow(['user01', '2000/01/01 00:00:00'])
#Lesen Sie alle geschriebenen Daten in Daten
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')
Im vorherigen Beispiel wird "tmpfile" verwendet, um eine Datei im Speicher zu erstellen, und dann wird "data" gelesen. Im Fall von AWS Lambda wird es jedoch in einer Umgebung ausgeführt, in der die Speichernutzung begrenzt ist. Wenn die Datei also groß wird, kann davon ausgegangen werden, dass die Speichernutzung erheblich beeinträchtigt wird. Natürlich ist dies ein Problem, das vermieden werden kann, indem die Obergrenze der Speichernutzung angehoben wird. Wenn sich die Gebühr jedoch verdoppelt, können Sie zögern.
In diesem Fall können Sie vorübergehend eine Datei unter "/ tmp" erstellen, die von AWS Lambda bereitgestellt wird, und die erstellte Datei in S3 hochladen.
Nach dem Hochladen auf S3 können Sie über die Kommunikation von CloudFront --S3
auf die erstellte Datei zugreifen oder eine temporäre URL erstellen und bereitstellen, über die der Benutzer sie herunterladen kann.
Beachten Sie, dass "TempfileContext" nicht die Essenz des Codes ist, da er so vorbereitet ist, dass die in AWS Lambda verwendeten Dateien unter "/ tmp" gelöscht werden können, ohne die Fehlerbehandlung zu berücksichtigen.
import os
import csv
import uuid
import boto3
s3 = boto3.client('s3')
class TempfileContext:
"""Bietet einen Kontext zum Erstellen und Löschen temporärer Dateien"""
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'):
"""So geben Sie eine CSV-Datei zurück 2:Erstellen Sie eine CSV und laden Sie sie in S3 hoch"""
with TempfileContext() as tmp:
# 1. /Erstellen Sie eine CSV-Datei im Bereich tmp
with open(tmp.filename, 'w', encoding=encoding) as fh:
#Schreiben Sie mit dem Schriftsteller
writer = csv.writer(fh, lineterminator='\n')
writer.writerow(['Nutzername', 'Datum und Uhrzeit der Anmeldung'])
writer.writerow(['user01', '2000/01/01 00:00:00'])
# 2.Auf S3 hochladen
s3.upload_file(tmp.filename, BUCKETNAME, f'uploads/{filename}')
Recommended Posts