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
class Posts(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False)
caption = models.TextField(max_length=1000)
media = models.ImageField(blank=True, default="", upload_to="posts/")
tags = models.ManyToManyField('Tags', related_name='posts')
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
class PostsViewset(viewsets.ModelViewSet):
serializer_class = PostsSerializer
#parser_classes = (MultipartJsonParser, parsers.JSONParser) use this if you have simple key value pair as data with no nested serializers
#parser_classes = (parsers.MultipartParser, parsers.JSONParser) use this if you want to parse json in the key value pair data sent
queryset = Posts.objects.all()
lookup_field = 'id'
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
from django.http import QueryDict
import json
from rest_framework import parsers
class MultipartJsonParser(parsers.MultiPartParser):
def parse(self, stream, media_type=None, parser_context=None):
result = super().parse(
stream,
media_type=media_type,
parser_context=parser_context
)
data = {}
# for case1 with nested serializers
# parse each field with json
for key, value in result.data.items():
if type(value) != str:
data[key] = value
continue
if '{' in value or "[" in value:
try:
data[key] = json.loads(value)
except ValueError:
data[key] = value
else:
data[key] = value
# for case 2
# find the data field and parse it
data = json.loads(result.data["data"])
qdict = QueryDict('', mutable=True)
qdict.update(data)
return parsers.DataAndFiles(qdict, result.files)
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