Po spędzeniu na tym 1 dnia doszedłem do wniosku, że ...
Dla kogoś, kto musi przesłać plik i wysłać dane, nie ma prostego sposobu, w jaki można go uruchomić. W specyfikacji API JSON występuje otwarty problem . Jedną z możliwości, które widziałem, jest użycie, multipart/related
jak pokazano tutaj , ale myślę, że bardzo trudno jest go zaimplementować w drf.
W końcu zaimplementowałem wysłanie żądania jako formdata
. Możesz wysłać każdy plik jako plik, a wszystkie inne dane jako tekst. Teraz, jeśli chodzi o wysyłanie danych jako tekst, masz dwie możliwości. przypadek 1) możesz wysłać każde dane jako parę klucz-wartość lub przypadek 2) możesz mieć pojedynczy klucz o nazwie data i wysłać cały plik json jako ciąg znaków w wartości.
Pierwsza metoda zadziałałaby po wyjęciu z pudełka, jeśli masz proste pola, ale będzie problemem, jeśli masz zagnieżdżone serializacje. Parser wieloczęściowy nie będzie w stanie przeanalizować zagnieżdżonych pól.
Poniżej przedstawiam implementację dla obu przypadków
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 -> nie są potrzebne żadne specjalne zmiany, nie pokazuję tutaj mojego serializatora jako zbyt długiego z powodu zapisywalnej implementacji pola ManyToMany.
views.py
class PostsViewset(viewsets.ModelViewSet):
serializer_class = PostsSerializer
queryset = Posts.objects.all()
lookup_field = 'id'
Teraz, jeśli postępujesz zgodnie z pierwszą metodą i wysyłasz tylko dane inne niż Json jako pary klucz-wartość, nie potrzebujesz niestandardowej klasy parsera. DRF'd MultipartParser wykona zadanie. Ale w drugim przypadku lub jeśli masz zagnieżdżone serializatory (jak pokazałem), będziesz potrzebować niestandardowego parsera, jak pokazano poniżej.
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 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
data = json.loads(result.data["data"])
qdict = QueryDict('', mutable=True)
qdict.update(data)
return parsers.DataAndFiles(qdict, result.files)
Ten serializator zasadniczo przeanalizowałby zawartość json w wartościach.
Przykład żądania w post man dla obu przypadków: sprawa 1 ,
Przypadek 2