Провівши 1 день на це, я зрозумів, що ...
Для когось, хто повинен завантажити файл і надіслати деякі дані, немає прямого способу, як ви можете змусити його працювати. Для цього у специфікаціях json api є відкрита проблема . Однією з можливостей, яку я бачив, є використання, multipart/related
як показано тут , але я думаю, що дуже важко реалізувати це в drf.
Нарешті, що я реалізував, це надіслати запит як formdata
. Ви б надсилали кожен файл як файл, а всі інші дані - як текст. Тепер для надсилання даних у вигляді тексту у вас є два варіанти. випадок 1) ви можете надіслати кожну інформацію як пару значень ключа або випадок 2) ви можете мати один ключ, який називається даними, і надіслати цілий 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.
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'
Тепер, якщо ви дотримуєтесь першого методу і надсилаєте лише дані, що не належать до 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 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)
Цей серіалізатор в основному буде аналізувати будь-який вміст json у значеннях.
Приклад запиту в поштовій службі для обох випадків: випадок 1 ,
Випадок 2