Потратив на это 1 день, я понял, что ...
Для тех, кому нужно загрузить файл и отправить некоторые данные, не существует прямого способа заставить его работать. Для этого есть открытая проблема в спецификациях json api. Одна из возможностей, которую я видел, - это использовать, multipart/related
как показано здесь , но я думаю, что это очень сложно реализовать в drf.
Наконец, я реализовал отправку запроса как formdata
. Вы должны отправить каждый файл как файл, а все остальные данные как текст. Теперь для отправки данных в виде текста у вас есть два варианта. случай 1) вы можете отправлять каждые данные как пару значений ключа или случай 2) вы можете иметь один ключ с именем data и отправлять весь json как строку в значении.
Первый метод будет работать из коробки, если у вас есть простые поля, но возникнет проблема, если у вас есть вложенные сериализации. Многокомпонентный синтаксический анализатор не сможет анализировать вложенные поля.
Ниже я предоставляю реализацию для обоих случаев.
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 -> никаких особых изменений не требуется, мой сериализатор здесь не показан, поскольку он слишком длинный из-за возможности записи ManyToMany Field.
views.py
class PostsViewset(viewsets.ModelViewSet):
serializer_class = PostsSerializer
queryset = Posts.objects.all()
lookup_field = 'id'
Теперь, если вы следуете первому методу и отправляете только данные, отличные от Json, в виде пар ключ-значение, вам не нужен специальный класс парсера. DRF'd MultipartParser выполнит эту работу. Но для второго случая или если у вас есть вложенные сериализаторы (как я показал), вам понадобится собственный парсер, как показано ниже.
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)
Этот сериализатор в основном анализирует любое содержимое json в значениях.
Пример запроса в почтовом ящике для обоих случаев: case 1 ,
Случай 2