Ich verwende Django Rest Framework und AngularJs, um eine Datei hochzuladen. Meine Ansichtsdatei sieht folgendermaßen aus:
class ProductList(APIView):
authentication_classes = (authentication.TokenAuthentication,)
def get(self,request):
if request.user.is_authenticated():
userCompanyId = request.user.get_profile().companyId
products = Product.objects.filter(company = userCompanyId)
serializer = ProductSerializer(products,many=True)
return Response(serializer.data)
def post(self,request):
serializer = ProductSerializer(data=request.DATA, files=request.FILES)
if serializer.is_valid():
serializer.save()
return Response(data=request.DATA)
Da die letzte Zeile der Post-Methode alle Daten zurückgeben sollte, habe ich mehrere Fragen:
- wie man prüft, ob etwas drin ist
request.FILES
? - Wie serialisiere ich ein Dateifeld?
- Wie soll ich Parser verwenden?
Antworten:
Verwenden Sie den FileUploadParser , alles ist in der Anfrage enthalten. Verwenden Sie stattdessen eine Put-Methode. Ein Beispiel finden Sie in den Dokumenten :)
quelle
Ich verwende denselben Stapel und habe auch nach einem Beispiel für das Hochladen von Dateien gesucht, aber mein Fall ist einfacher, da ich das ModelViewSet anstelle von APIView verwende. Der Schlüssel stellte sich als pre_save-Hook heraus. Am Ende habe ich es zusammen mit dem Angular-File-Upload-Modul wie folgt verwendet:
quelle
Endlich kann ich mit Django ein Bild hochladen. Hier ist mein Arbeitscode
views.py
urls.py
Curl-Anfrage zum Hochladen
quelle
with open('/Users/Username/' + up_file.name, 'wb+') as destination:
, den Verschluss vollständig zu verwenden und zu entfernenModelViewSet
. Außerdem haben sie es höchstwahrscheinlich besser umgesetzt.FileUploadParser
erforderlich ist, aberMultiPartParser
!Nachdem ich einen Tag damit verbracht hatte, stellte ich fest, dass ...
Für jemanden, der eine Datei hochladen und einige Daten senden muss, gibt es keine direkte Möglichkeit, sie zum Laufen zu bringen. Hierfür gibt es ein offenes Problem in den JSON-API-Spezifikationen. Eine Möglichkeit, die ich gesehen habe, ist die Verwendung
multipart/related
wie hier gezeigt , aber ich denke, es ist sehr schwierig, sie in drf zu implementieren.Schließlich hatte ich implementiert, die Anfrage als zu senden
formdata
. Sie würden jede Datei als Datei und alle anderen Daten als Text senden . Jetzt haben Sie zwei Möglichkeiten, um die Daten als Text zu senden. Fall 1) Sie können jede Daten als Schlüsselwertpaar senden oder Fall 2) Sie können einen einzelnen Schlüssel namens Daten haben und den gesamten JSON als Wertzeichenfolge senden.Die erste Methode funktioniert sofort, wenn Sie einfache Felder haben, ist jedoch ein Problem, wenn Sie verschachtelte Serialisierungen haben. Der mehrteilige Parser kann die verschachtelten Felder nicht analysieren.
Im Folgenden stelle ich die Implementierung für beide Fälle bereit
Models.py
serializers.py -> Es sind keine besonderen Änderungen erforderlich. Mein Serializer wird hier aufgrund der beschreibbaren Implementierung von ManyToMany Field nicht als zu lang angezeigt.
views.py
Wenn Sie nun der ersten Methode folgen und nur Nicht-Json-Daten als Schlüsselwertpaare senden, benötigen Sie keine benutzerdefinierte Parser-Klasse. DRF'd MultipartParser erledigt den Job. Aber für den zweiten Fall oder wenn Sie verschachtelte Serializer haben (wie ich gezeigt habe), benötigen Sie einen benutzerdefinierten Parser wie unten gezeigt.
utils.py
Dieser Serializer würde grundsätzlich jeden JSON-Inhalt in den Werten analysieren.
Das Anforderungsbeispiel in Postman für beide Fälle: Fall 1 ,
Fall 2
quelle
Ich habe dieses Problem mit ModelViewSet und ModelSerializer gelöst. Hoffe das wird der Community helfen.
Ich bevorzuge auch die Validierung und die Anmeldung von Object-> JSON (und umgekehrt) im Serializer selbst und nicht in Ansichten.
Verstehen wir es anhand eines Beispiels.
Angenommen, ich möchte eine FileUploader-API erstellen. Hier werden Felder wie ID, Dateipfad, Dateiname, Größe, Eigentümer usw. in der Datenbank gespeichert. Siehe Beispielmodell unten:
Für APIs möchte ich Folgendes:
Wenn ich den GET-Endpunkt starte, möchte ich alle oben genannten Felder für jede hochgeladene Datei.
Damit der Benutzer eine Datei erstellen / hochladen kann, muss er sich darum kümmern, alle diese Felder zu übergeben. Sie kann einfach die Datei hochladen und dann kann der Serializer vermutlich die restlichen Felder aus der hochgeladenen DATEI abrufen.
Searilizer: Frage: Ich habe unten einen Serializer erstellt, um meinen Zweck zu erfüllen. Aber nicht sicher, ob es der richtige Weg ist, es zu implementieren.
Viewset als Referenz:
quelle
FileUploaderSerializer.validate
Methode?Nach meiner Erfahrung müssen Sie nichts Besonderes an Dateifeldern tun, sondern müssen nur das Dateifeld verwenden:
und Sie können Dateien hochladen:
Fügen Sie
-F field=value
für jedes zusätzliche Feld Ihres Modells hinzu. Und vergessen Sie nicht, die Authentifizierung hinzuzufügen.quelle
Wenn jemand an dem einfachsten Beispiel mit ModelViewset für Django Rest Framework interessiert ist.
Das Modell ist,
Der Serializer,
Und die Ansicht ist,
Test im Postboten,
quelle
Im Django-Rest-Framework werden Anforderungsdaten von der analysiert
Parsers
.http://www.django-rest-framework.org/api-guide/parsers/
Standardmäßig verwendet das django-rest-Framework die Parser-Klasse
JSONParser
. Die Daten werden in json analysiert. Daher werden Dateien nicht damit analysiert.Wenn Dateien zusammen mit anderen Daten analysiert werden sollen, sollten wir eine der folgenden Parser-Klassen verwenden.
quelle
application/json
,application/x-www-form-urlencoded
undmultipart/form-data
.quelle
quelle
Ich möchte eine weitere Option schreiben, die meiner Meinung nach sauberer und einfacher zu warten ist. Wir werden den defaultRouter verwenden, um CRUD-URLs für unser Viewset hinzuzufügen, und wir werden eine weitere feste URL hinzufügen, die die Uploader-Ansicht innerhalb desselben Viewset angibt.
Haupt-URLs des Projekts
.- LIESMICH.
Die Magie entsteht, wenn wir unserer Klassenmethode 'Uploader' @action decorator hinzufügen. Durch Angabe des Arguments "Methods = ['put']" werden nur PUT-Anforderungen zugelassen. Perfekt zum Hochladen von Dateien.
Ich habe auch das Argument "parser_classes" hinzugefügt, um zu zeigen, dass Sie den Parser auswählen können, der Ihren Inhalt analysiert. Ich habe CSVParser aus dem Paket rest_framework_csv hinzugefügt, um zu demonstrieren, wie wir nur bestimmte Dateitypen akzeptieren können, wenn diese Funktionalität erforderlich ist. In meinem Fall akzeptiere ich nur "Content-Type: text / csv". Hinweis: Wenn Sie benutzerdefinierte Parser hinzufügen, müssen Sie diese in parsers_classes im ViewSet angeben, da die Anforderung den zulässigen Medientyp mit Hauptparsern (Klassenparsern) vergleicht, bevor Sie auf die Parser der Uploader-Methode zugreifen.
Jetzt müssen wir Django sagen, wie er zu dieser Methode gehen soll und wo sie in unseren URLs implementiert werden kann. Dann fügen wir die feste URL hinzu (einfache Zwecke). Diese URL verwendet ein "Dateinamen" -Argument, das später in der Methode übergeben wird. Wir müssen diese Methode "Uploader" übergeben und das http-Protokoll ('PUT') in einer Liste an die PostsViewSet.as_view-Methode angeben.
Wenn wir in der folgenden URL landen
Es wird eine PUT-Anforderung mit Headern erwartet, in denen "Inhaltstyp" und Inhaltsdisposition angegeben sind: Anhang; Dateiname = "etwas.csv".
quelle
parser_classes
ist nicht da, um zu begrenzen, welche Dateien hochgeladen werden können. Hier können Sie entscheiden, in welchen Formaten Anforderungen gestellt werden können. Auf den zweiten Blick, wie Sie mit dem Upload umgehen ... es scheint, als würden Sie Daten aus CSV in die Datenbank stellen. Nicht was OP gefragt hat.Dies ist der Ansatz, den ich angewendet habe, hoffentlich hilft er.
quelle
Sie können die Antwort von @ Nithin verallgemeinern, um direkt mit dem vorhandenen Serializer-System von DRF zu arbeiten, indem Sie eine Parser-Klasse generieren, um bestimmte Felder zu analysieren, die dann direkt in die Standard-DRF-Serializer eingespeist werden:
Dies wird verwendet wie:
quelle
Wenn Sie ModelViewSet verwenden, sind Sie tatsächlich fertig! Es erledigt alles für Sie! Sie müssen nur das Feld in Ihren ModelSerializer einfügen und
content-type=multipart/form-data;
in Ihrem Client festlegen .ABER wie Sie wissen, können Sie keine Dateien im JSON-Format senden. (Wenn der Inhaltstyp in Ihrem Client auf application / json eingestellt ist). Es sei denn, Sie verwenden das Base64-Format.
Sie haben also zwei Möglichkeiten:
ModelViewSet
undModelSerializer
bearbeiten Sie den Job und senden Sie die Anfrage mitcontent-type=multipart/form-data;
ModelSerializer
asBase64ImageField (or) Base64FileField
und weisen Sie Ihren Client an, die Datei zu codierenBase64
und zu setzencontent-type=application/json
quelle
models.py
serializers.py
views.py
urls.py
settings.py
Senden Sie eine Post-Anfrage an
api/files
mit einer an einform-data
Feld angehängten Dateifile
. Die Datei wird in einen/media
Ordner hochgeladen und ein Datenbankdatensatz mit ID und Dateiname hinzugefügt.quelle