J'utilise Django Rest Framework et AngularJs pour télécharger un fichier. Mon fichier de vue ressemble à ceci:
class ProductList(APIView):
authentication_classes = (authentication.TokenAuthentication,)
def get(self,request):
if request.user.is_authenticated():
userCompanyId = request.user.get_profile().companyId
products = Product.objects.filter(company = userCompanyId)
serializer = ProductSerializer(products,many=True)
return Response(serializer.data)
def post(self,request):
serializer = ProductSerializer(data=request.DATA, files=request.FILES)
if serializer.is_valid():
serializer.save()
return Response(data=request.DATA)
Comme la dernière ligne de la méthode de publication doit renvoyer toutes les données, j'ai plusieurs questions:
- comment vérifier s'il y a quelque chose dedans
request.FILES
? - comment sérialiser le champ de fichier?
- comment utiliser l'analyseur?
Réponses:
Utilisez FileUploadParser , tout est dans la requête. Utilisez plutôt une méthode put, vous trouverez un exemple dans la documentation :)
la source
J'utilise la même pile et je cherchais également un exemple de téléchargement de fichier, mais mon cas est plus simple puisque j'utilise ModelViewSet au lieu d'APIView. La clé s'est avérée être le hook pre_save. J'ai fini par l'utiliser avec le module angular-file-upload comme ceci:
la source
Enfin, je suis capable de télécharger une image en utilisant Django. Voici mon code de travail
views.py
urls.py
curl demande de téléchargement
la source
with open('/Users/Username/' + up_file.name, 'wb+') as destination:
et de supprimer complètement la clôtureModelViewSet
. En outre, ils l'ont probablement mieux mis en œuvre.FileUploadParser
nécessaire, maisMultiPartParser
!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
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
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
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
la source
J'ai résolu ce problème avec ModelViewSet et ModelSerializer. J'espère que cela aidera la communauté.
Je préfère également avoir la validation et la connexion Object-> JSON (et vice-versa) dans le sérialiseur lui-même plutôt que dans les vues.
Permet de comprendre par exemple.
Dites, je veux créer l'API FileUploader. Où il stockera des champs tels que id, chemin_fichier, nom_fichier, taille, propriétaire, etc. dans la base de données. Voir l'exemple de modèle ci-dessous:
Maintenant, pour les API, c'est ce que je veux:
Lorsque je déclenche le point de terminaison GET, je veux tous les champs ci-dessus pour chaque fichier téléchargé.
Mais pour que l'utilisateur crée / télécharge un fichier, pourquoi elle doit s'inquiéter de passer tous ces champs. Elle peut simplement télécharger le fichier et ensuite, je suppose, le sérialiseur peut obtenir le reste des champs du FICHIER téléchargé.
Searilizer: Question: J'ai créé ci-dessous le sérialiseur pour servir mon objectif. Mais je ne sais pas si c'est la bonne façon de le mettre en œuvre.
Ensemble de vues pour référence:
la source
FileUploaderSerializer.validate
méthode contient-elle?D'après mon expérience, vous n'avez rien à faire de particulier concernant les champs de fichier, vous lui dites simplement d'utiliser le champ de fichier:
et vous êtes prêt à télécharger des fichiers:
Ajoutez
-F field=value
pour chaque champ supplémentaire de votre modèle. Et n'oubliez pas d'ajouter l'authentification.la source
Si quelqu'un est intéressé par l'exemple le plus simple avec ModelViewset pour Django Rest Framework.
Le modèle est,
Le sérialiseur,
Et la vue est,
Test chez Postman,
la source
Dans la requête django-rest-framework, les données sont analysées par le
Parsers
.http://www.django-rest-framework.org/api-guide/parsers/
Par défaut, django-rest-framework prend la classe parser
JSONParser
. Il analysera les données dans json. ainsi, les fichiers ne seront pas analysés avec.Si nous voulons que les fichiers soient analysés avec d'autres données, nous devons utiliser l'une des classes d'analyseurs ci-dessous.
la source
application/json
,application/x-www-form-urlencoded
etmultipart/form-data
.la source
la source
J'aimerais écrire une autre option qui me semble plus propre et plus facile à entretenir. Nous utiliserons le defaultRouter pour ajouter des URL CRUD pour notre ensemble de vues et nous ajouterons une autre URL fixe spécifiant la vue de téléchargement dans le même ensemble de vues.
Principales urls.py du projet
.- LISEZ-MOI.
La magie se produit lorsque nous ajoutons @action decorator à notre méthode de classe 'uploader'. En spécifiant l'argument "methods = ['put']", nous n'autorisons que les requêtes PUT; parfait pour le téléchargement de fichiers.
J'ai également ajouté l'argument "parser_classes" pour montrer que vous pouvez sélectionner l'analyseur qui analysera votre contenu. J'ai ajouté CSVParser à partir du package rest_framework_csv, pour montrer comment nous pouvons accepter uniquement certains types de fichiers si cette fonctionnalité est requise, dans mon cas, j'accepte uniquement "Content-Type: text / csv". Remarque: Si vous ajoutez des analyseurs personnalisés, vous devrez les spécifier dans parsers_classes dans le ViewSet car la requête comparera le media_type autorisé avec les analyseurs principaux (de classe) avant d'accéder aux analyseurs de méthode de téléchargement.
Nous devons maintenant dire à Django comment accéder à cette méthode et où peut être implémentée dans nos URL. C'est à ce moment que nous ajoutons l'url fixe (à des fins simples). Cette URL prendra un argument "filename" qui sera passé dans la méthode plus tard. Nous devons passer cette méthode "uploader", en spécifiant le protocole http ('PUT') dans une liste à la méthode PostsViewSet.as_view.
Lorsque nous atterrissons dans l'url suivante
il attendra une requête PUT avec des en-têtes spécifiant "Content-Type" et Content-Disposition: attachment; filename = "quelque chose.csv".
la source
parser_classes
n'est pas là pour limiter les fichiers pouvant être téléchargés. Cela vous permet de décider quels formats peuvent être utilisés pour faire des demandes. Après réflexion, la façon dont vous gérez le téléchargement ... il semble que vous mettez des données CSV dans une base de données. Pas ce que OP a demandé.C'est celle de l'approche que j'ai appliquée, j'espère qu'elle aidera.
la source
Vous pouvez généraliser la réponse de @ Nithin pour travailler directement avec le système de sérialiseur existant de DRF en générant une classe d'analyseur pour analyser des champs spécifiques qui sont ensuite introduits directement dans les sérialiseurs DRF standard:
Ceci est utilisé comme:
la source
Si vous utilisez ModelViewSet, vous avez terminé! Il gère tout pour vous! Il vous suffit de mettre le champ dans votre ModelSerializer et de le définir
content-type=multipart/form-data;
dans votre client.MAIS comme vous le savez, vous ne pouvez pas envoyer de fichiers au format json. (lorsque content-type est défini sur application / json dans votre client). Sauf si vous utilisez le format Base64.
Vous avez donc deux choix:
ModelViewSet
etModelSerializer
gérez le travail et envoyez la demande en utilisantcontent-type=multipart/form-data;
ModelSerializer
commeBase64ImageField (or) Base64FileField
et indiquez à votre client d'encoder le fichierBase64
et de définir lecontent-type=application/json
la source
models.py
serializers.py
views.py
urls.py
settings.py
Envoyez une demande de publication à
api/files
avec votre fichier joint à unform-data
champfile
. Le fichier sera téléchargé dans le/media
dossier et un enregistrement de base de données sera ajouté avec l'identifiant et le nom du fichier.la source