Après avoir passé 1 jour là-dessus, j'ai compris que ...
Pour quelqu'un qui a besoin de télécharger un fichier et d'envoyer des données, il n'y a pas de moyen direct de le faire fonctionner. Il y a un problème ouvert dans les spécifications de l'API json pour cela. Une possibilité que j'ai vue est d'utiliser multipart/related
comme indiqué ici , mais je pense que c'est très difficile de l'implémenter dans drf.
Enfin, ce que j'avais mis en œuvre était d'envoyer la demande sous forme de fichier formdata
. Vous enverriez chaque fichier sous forme de fichier et toutes les autres données sous forme de texte. Maintenant, pour envoyer les données sous forme de texte, vous avez deux choix. cas 1) vous pouvez envoyer chaque donnée sous forme de paire clé / valeur ou cas 2) vous pouvez avoir une seule clé appelée data et envoyer le json entier sous forme de chaîne de valeur.
La première méthode fonctionnerait hors de la boîte si vous avez des champs simples, mais sera un problème si vous avez des sérialisations imbriquées. L'analyseur en plusieurs parties ne pourra pas analyser les champs imbriqués.
Ci-dessous, je fournis la mise en œuvre pour les deux cas
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 -> aucune modification spéciale n'est nécessaire, ne montrant pas mon sérialiseur ici comme étant trop long à cause de l'implémentation du champ ManyToMany inscriptible.
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'
Maintenant, si vous suivez la première méthode et n'envoyez que des données non Json sous forme de paires clé / valeur, vous n'avez pas besoin d'une classe d'analyseur personnalisée. DRF'd MultipartParser fera le travail. Mais pour le deuxième cas ou si vous avez des sérialiseurs imbriqués (comme je l'ai montré), vous aurez besoin d'un analyseur personnalisé comme indiqué ci-dessous.
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)
Ce sérialiseur analyserait essentiellement tout contenu json dans les valeurs.
L'exemple de requête dans post man pour les deux cas: cas 1 ,
Cas 2