Je veux juste créer une API REST qui reçoit un fichier, le traite et renvoie des informations. Mon problème est que je suis cet exemple: http://www.Django-rest-framework.org/api-guide/parsers/#fileuploadparser
Et je ne peux pas le faire fonctionner avec Postman ou Curl, je pense que quelque chose me manque. L'analyseur me donne toujours ces deux erreurs:
C'est le code:
views.py:
class FileUploadView(APIView):
parser_classes = (FileUploadParser,)
def post(self, request, filename, format=None):
file_obj = request.data['file']
# ...
# do some stuff with uploaded file
# ...
return Response(status=204)
def put(self, request, filename, format=None):
file_obj = request.data['file']
# ...
# do some stuff with uploaded file
# ...
return Response(status=204)
urls.py
urlpatterns = [
url(r'predict/(?P<filename>[^/]+)$', app.views.FileUploadView.as_view())
]
settings.py
"""
Django settings for GenderAPI project.
Generated by 'Django-admin startproject' using Django 1.9.1.
For more information on this file, see
https://docs.djangoproject.com/en/1.9/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.9/ref/settings/
"""
import os
import posixpath
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'file': {
'level': 'DEBUG',
'class': 'logging.FileHandler',
'filename': 'debug.log',
},
},
'loggers': {
'Django': {
'handlers': ['file'],
'level': 'DEBUG',
'propagate': True,
},
},
}
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = removed
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ['localhost','127.0.0.1']
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': (
'rest_framework.parsers.FileUploadParser'
)
}
# Application definition
INSTALLED_APPS = [
# Add your apps here to enable them
'Django.contrib.admin',
'Django.contrib.auth',
'Django.contrib.contenttypes',
'Django.contrib.sessions',
'Django.contrib.messages',
'Django.contrib.staticfiles',
'rest_framework',
'app'
]
MIDDLEWARE = [
'Django.middleware.security.SecurityMiddleware',
'Django.contrib.sessions.middleware.SessionMiddleware',
'Django.middleware.common.CommonMiddleware',
'Django.middleware.csrf.CsrfViewMiddleware',
'Django.contrib.auth.middleware.AuthenticationMiddleware',
'Django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'Django.contrib.messages.middleware.MessageMiddleware',
'Django.middleware.clickjacking.XFrameOptionsMiddleware'
]
ROOT_URLCONF = 'GenderAPI.urls'
TEMPLATES = [
{
'BACKEND': 'Django.template.backends.Django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'Django.template.context_processors.debug',
'Django.template.context_processors.request',
'Django.contrib.auth.context_processors.auth',
'Django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'GenderAPI.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.9/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'Django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.9/howto/static-files/
STATIC_URL = '/static/'
STATIC_ROOT = posixpath.join(*(BASE_DIR.split(os.path.sep) + ['static']))
FILE_UPLOAD_TEMP_DIR = BASE_DIR
MEDIA_URL = '/media/'
Ici vous pouvez voir une capture de postier (j'ai tout essayé):
PUT /predict/pabloGrande.jpg HTTP/1.1
Host: 127.0.0.1:52276
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="04320cf.jpg"
Content-Type: image/jpeg
------WebKitFormBoundary7MA4YWxkTrZu0gW--
exigences:
bleach==1.5.0
Django==1.11.6
djangorestframework==3.7.1
html5lib==0.9999999
Markdown==2.6.9
numpy==1.13.3
olefile==0.44
pandas==0.20.3
Pillow==4.3.0
pip==9.0.1
protobuf==3.4.0
python-dateutil==2.6.1
pytz==2017.2
scipy==1.0.0rc1
setuptools==28.8.0
six==1.11.0
tensorflow==1.3.0
tensorflow-tensorboard==0.1.8
Werkzeug==0.12.2
wheel==0.30.0
Merci beaucoup pour votre aide
Dans Django REST framework. nous avons des composants comme les analyseurs syntaxiques, les moteurs de rendu et les sérialiseurs.
La responsabilité des analyseurs est d’analyser les données envoyées par les méthodes de requête GET, POST et PUT, etc.
L'analyseur par défaut utilisé dans Django REST est ' JSONParser '. Il analyse uniquement les données JSON de données [nombres, chaîne, date]. Il ignore les données comme les fichiers.
Pour analyser les fichiers, nous devons utiliser des analyseurs tels que " MultiPartParser " ou " FormParser ".
Exemple de code:
from rest_framework.parsers import MultiPartParser
from rest_framework.response import Response
from rest_framework.views import APIView
class ExampleView(APIView):
"""
A view that can accept POST requests with JSON content.
"""
parser_classes = (MultiPartParser,)
def post(self, request, format=None):
# to access files
print request.FILES
# to access data
print request.data
return Response({'received data': request.data})
Lorsque nous utilisons la propriété request.data
, l'analyseur analysera les données.
Références: Django REST Docs , Django REST Github
Je suis confronté au même problème. Le message d’erreur indique:
{"detail": "Nom de fichier manquant. La requête doit inclure un en-tête Content-Disposition avec un paramètre de nom de fichier."} Je fais toutes les étapes au-dessus de ma réponse mais cela ne fonctionne pas.Enfin ,
Je trouve que la raison est dans le backend de viewset.
ça se voit comme ça
parser_classes = (FileUploadParser, MultiPartParser, FormParser)
et je supprime le FileUploadParser
parser_classes = ( MultiPartParser, FormParser)
et ça marche, alors je pense que vous devriez y prêter plus d'attention
dans votre views.py changer l'analyseur comme celui-ci
parser_classes = (JSONParser, MultiPartParser)
Sur la deuxième erreur Missing filename. Request should include a Content-Disposition header with a filename parameter.
utilisant postman, j'ai supprimé l'en-tête Content-Type :multipart/form-data
et j'ai réussi.
Il semble que le problème est que l'en-tête Content-Type personnalisé remplace l'en-tête Content-Type par défaut à envoyer. Vérifiez ce fil pour référence Content-Type pour les messages en plusieurs parties
Vous n'avez pas besoin d'utiliser MultipartParser
ou FormParser
.
Ce dont vous avez besoin est un sérialiseur avec une FileField()
comme ceci:
serializers.py:
class FileUploadSerializer(serializers.Serializer):
# I set use_url to False so I don't need to pass file
# through the url itself - defaults to True if you need it
file = serializers.FileField(use_url=False)
Ainsi, lorsque vous essayez d'accéder à file
ci-dessous, vous obtenez un dict avec une clé nommée file
. Personnellement, je dirais probablement quelque chose de plus descriptif que simplement "fichier", mais cela dépend de vous.
from .serializers import FileUploadSerializer
class FileUploadView(APIView):
def post(self, request):
# set 'data' so that you can use 'is_vaid()' and raise exception
# if the file fails validation
serializer = FileUploadSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
# once validated, grab the file from the request itself
file = request.FILES['file']