Die Verarbeitung eines Django UploadedFile als UTF-8 mit universal-newlines
In meinem django-Anwendung habe ich ein Formular bereitstellen, die es Benutzern ermöglicht, eine Datei hochzuladen. Die Datei kann in verschiedenen Formaten (Excel, CSV), kommen aus einer Vielzahl von Plattformen (Mac, Linux, Windows), und codiert werden, in eine Vielzahl von Zeichenkodierungen (ASCII, UTF-8).
Für die Zwecke dieser Frage, lassen Sie uns davon ausgehen, dass ich eine Ansicht, die den Empfang request.FILES['file']
eine Instanz von InMemoryUploadedFile
genannt file
. Mein problem ist, dass InMemoryUploadedFile
Objekte (wie file
):
- Nicht unterstützt UTF-8-Kodierung (ich sehe ein
\xef\xbb\xbf
am Anfang der Datei, die so wie ich das verstehe ist ein flag, das bedeutet "diese Datei ist UTF-8'). - Nicht unterstützen universal-newlines (was wohl die Mehrheit der hochgeladenen Dateien, die auf dieses system benötigen).
Verkompliziert das Problem ist, dass ich wünschte, um übergeben Sie die Datei in der python - csv
- Modul, das bietet keine native Unterstützung für Unicode. Ich glücklich akzeptieren Sie Antworten, vermeiden Sie dieses Problem - wenn ich mit django spielen schön mit UTF-8 ich bin sicher, ich kann Keule csv
in das gleiche tun. (Ähnlich, bitte ignorieren Sie die Anforderung zur Unterstützung von Excel - ich warte, bis CSV funktioniert, bevor ich angehen Parsen von Excel-Dateien.)
Habe ich versucht, mit StringIO
,mmap
,codec
, und jede einer Vielzahl von Möglichkeiten, auf die Daten in einer InMemoryUploadedFile
Objekt. Jeder Ansatz hat ergab unterschiedliche Fehler, keiner ist so weit perfekt gewesen. Dieser zeigt einige der code, den ich fühle, kam der nächste:
import csv
import codecs
class CSVParser:
def __init__(self,file):
# 'file' is assumed to be an InMemoryUploadedFile object.
dialect = csv.Sniffer().sniff(codecs.EncodedFile(file,"utf-8").read(1024))
file.open() # seek to 0
self.reader = csv.reader(codecs.EncodedFile(file,"utf-8"),
dialect=dialect)
try:
self.field_names = self.reader.next()
except StopIteration:
# The file was empty - this is not allowed.
raise ValueError('Unrecognized format (empty file)')
if len(self.field_names) <= 1:
# This probably isn't a CSV file at all.
# Note that the csv module will (incorrectly) parse ALL files, even
# binary data. This will catch most such files.
raise ValueError('Unrecognized format (too few columns)')
# Additional methods snipped, unrelated to issue
Bitte beachten Sie, dass ich nicht zu viel Zeit auf die eigentliche parsing-Algorithmus, so kann es Wild ineffizient, momentan bin ich mehr mit immer besorgt die Codierung funktioniert wie erwartet.
Das problem ist, dass die Ergebnisse sind auch nicht verschlüsselt, obwohl eingewickelt in die Unicode - codecs.EncodedFile
Datei wrapper.
EDIT: Es stellt sich heraus, der obige code funktioniert in der Tat Arbeit. codecs.EncodedFile(file,"utf-8")
ist das ticket. Es stellt sich heraus, der Grund, warum ich dachte, dass es nicht funktioniert hat, war, dass die terminal-ich war mit unterstützt nicht UTF-8. Leben und lernen!
- Ich hatte eine wirklich harte Zeit immer den <code> block zu stoppen kauen bis die '<' und '>' - Zeichen. (Weniger-als und größer-als -, wenn Sie gekaut, bis auch hier.)
- Ok, nach einiger Zeit der Suche in dieser, es stellt sich heraus, dass der code, den ich oben gepostet hat, in der Tat, Arbeit. Es stellt sich heraus, dass die control-Zeichen, die ich sah, waren da die terminal-ich war mit zu erfassen debug print-Anweisungen nicht unterstützt, ist UTF-8. Woops!
- Schöne Arbeit, eblume!
Du musst angemeldet sein, um einen Kommentar abzugeben.
Wie oben erwähnt, das code-snippet, ich war in der Tat wie vorgesehen funktioniert - das problem war mit meinem terminal, und nicht mit python-Codierung.
Wenn Ihr view-Zugriff auf eine UTF-8
UploadedFile
Sie können einfach verwenden Sieutf8_file = codecs.EncodedFile(request.FILES['file_field'],"utf-8")
zum öffnen einer Datei-Objekt in der richtigen Codierung.Mir ist auch aufgefallen, dass, zumindest für
InMemoryUploadedFile
s, öffnen der Datei durch diecodecs.EncodedFile
wrapper wird NICHT zurückgestelltseek()
position der Datei-Deskriptor. Zurück an den Anfang der Datei (wieder, dies kannInMemoryUploadedFile
spezifisch) habe ich nur verwendetrequest.FILES['file_field'].open()
zu senden, dieseek()
position wieder auf 0.can't use a string pattern on a bytes-like object
mit der Liniedialect = csv.Sniffer().sniff(codecs.EncodedFile(file,"utf-8").read(1024))
. Ich fügtedecode()
nachread()
dann bekomme ich Fehleriterator should return strings, not bytes
geben, wenn ichnext(reader)
. Was ist falsch?Ich die csv.DictReader und es scheint gut zu funktionieren. Ich legte mein code-snippet, aber es ist im Grunde das gleiche wie ein anderer hier beantworten.
Für CSV-und Excel-upload zu django, diese Website kann helfen.