Estoy usando Django Rest Framework y AngularJs para cargar un archivo. Mi archivo de vista se ve así:
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)
Como la última línea del método de publicación debería devolver todos los datos, tengo varias preguntas:
- cómo comprobar si hay algo en
request.FILES
? - ¿Cómo serializar el campo del archivo?
- ¿Cómo debo usar el analizador?
Respuestas:
Utilice FileUploadParser , todo está en la solicitud. Use un método put en su lugar, encontrará un ejemplo en los documentos :)
fuente
Estoy usando la misma pila y también estaba buscando un ejemplo de carga de archivos, pero mi caso es más simple ya que uso ModelViewSet en lugar de APIView. La clave resultó ser el gancho pre_save. Terminé usándolo junto con el módulo de carga de archivos angulares así:
fuente
Finalmente puedo subir una imagen usando Django. Aquí está mi código de trabajo
views.py
urls.py
solicitud curl para cargar
fuente
with open('/Users/Username/' + up_file.name, 'wb+') as destination:
y eliminar el cierre por completoModelViewSet
. Además, lo más probable es que lo hayan implementado mejor.FileUploadParser
es necesario,MultiPartParser
¡ sino !Después de pasar 1 día en esto, descubrí que ...
Para alguien que necesita cargar un archivo y enviar algunos datos, no existe una forma directa de hacer que funcione. Hay un problema abierto en las especificaciones de la api json para esto. Una posibilidad que he visto es usarlo
multipart/related
como se muestra aquí , pero creo que es muy difícil implementarlo en drf.Finalmente lo que había implementado era enviar la solicitud como
formdata
. Enviaría cada archivo como archivo y todos los demás datos como texto. Ahora, para enviar los datos como texto, tiene dos opciones. caso 1) puede enviar cada dato como par clave-valor o caso 2) puede tener una sola clave llamada datos y enviar todo el json como cadena en valor.El primer método funcionaría de inmediato si tiene campos simples, pero será un problema si tiene serializaciones anidadas. El analizador multiparte no podrá analizar los campos anidados.
A continuación, proporciono la implementación para ambos casos.
Models.py
serializers.py -> no se necesitan cambios especiales, no muestra mi serializador aquí porque es demasiado largo debido a la implementación de campo ManyToMany que se puede escribir.
views.py
Ahora, si está siguiendo el primer método y solo envía datos que no son de Json como pares clave-valor, no necesita una clase de analizador personalizada. DRF'd MultipartParser hará el trabajo. Pero para el segundo caso o si tiene serializadores anidados (como he mostrado), necesitará un analizador personalizado como se muestra a continuación.
utils.py
Este serializador básicamente analizaría cualquier contenido json en los valores.
El ejemplo de solicitud en post man para ambos casos: caso 1 ,
Caso 2
fuente
Resolví este problema con ModelViewSet y ModelSerializer. Espero que esto ayude a la comunidad.
También prefiero tener validación y Object-> JSON (y viceversa) en el serializador en lugar de en las vistas.
Entendamos con el ejemplo.
Diga, quiero crear FileUploader API. Donde almacenará campos como id, file_path, file_name, size, owner, etc.en la base de datos. Vea el modelo de muestra a continuación:
Ahora, para las API, esto es lo que quiero:
Cuando disparo el punto final GET, quiero todos los campos anteriores para cada archivo cargado.
Pero para que el usuario cree / cargue un archivo, tiene que preocuparse por pasar todos estos campos. Ella puede simplemente cargar el archivo y luego, supongo, el serializador puede obtener el resto de los campos del ARCHIVO cargado.
Searilizer: Pregunta: Creé el siguiente serializador para cumplir mi propósito. Pero no estoy seguro de si es la forma correcta de implementarlo.
Viewset para referencia:
fuente
FileUploaderSerializer.validate
contiene el método?Desde mi experiencia, no necesita hacer nada en particular sobre los campos de archivo, solo dígale que use el campo de archivo:
y ya está listo para cargar archivos:
Agregue
-F field=value
por cada campo adicional que tenga su modelo. Y no olvide agregar autenticación.fuente
Si alguien está interesado en el ejemplo más fácil con ModelViewset para Django Rest Framework.
El modelo es,
El serializador,
Y la vista es,
Prueba en cartero,
fuente
En django-rest-framework, los datos de la solicitud son analizados por
Parsers
.http://www.django-rest-framework.org/api-guide/parsers/
De forma predeterminada, django-rest-framework toma la clase de analizador
JSONParser
. Analizará los datos en json. por lo tanto, los archivos no se analizarán con él.Si queremos que los archivos se analicen junto con otros datos, debemos usar una de las clases de analizador siguientes.
fuente
application/json
,application/x-www-form-urlencoded
ymultipart/form-data
.fuente
fuente
Me gustaría escribir otra opción que creo que es más limpia y más fácil de mantener. Usaremos el defaultRouter para agregar URL CRUD para nuestro conjunto de vistas y agregaremos una URL fija más especificando la vista del cargador dentro del mismo conjunto de vistas.
URL principal del proyecto.
.- README.
La magia sucede cuando agregamos @action decorator a nuestro método de clase 'uploader'. Al especificar el argumento "métodos = ['poner']", solo permitimos solicitudes PUT; perfecto para cargar archivos.
También agregué el argumento "parser_classes" para mostrar que puede seleccionar el analizador que analizará su contenido. Agregué CSVParser del paquete rest_framework_csv, para demostrar cómo podemos aceptar solo cierto tipo de archivos si se requiere esta funcionalidad, en mi caso solo acepto "Content-Type: text / csv". Nota: Si está agregando analizadores personalizados, deberá especificarlos en parsers_classes en ViewSet debido a que la solicitud comparará el media_type permitido con los analizadores principales (clase) antes de acceder a los analizadores del método de carga.
Ahora necesitamos decirle a Django cómo ir a este método y dónde se puede implementar en nuestras URL. Ahí es cuando agregamos la URL fija (propósitos simples). Esta URL tomará un argumento de "nombre de archivo" que se pasará en el método más adelante. Necesitamos pasar este método "uploader", especificando el protocolo http ('PUT') en una lista al método PostsViewSet.as_view.
Cuando aterrizamos en la siguiente URL
esperará una solicitud PUT con encabezados que especifiquen "Content-Type" y Content-Disposition: adjunto; nombre de archivo = "algo.csv".
fuente
parser_classes
no está ahí para limitar qué archivos se pueden cargar. Le permite decidir qué formatos se pueden usar para realizar solicitudes. Pensándolo bien, la forma en que maneja la carga ... parece que está poniendo datos de CSV en la base de datos. No es lo que pidió OP.Este es uno de los enfoques que he aplicado, espero que ayude.
fuente
Puede generalizar la respuesta de @ Nithin para que funcione directamente con el sistema de serializador existente de DRF generando una clase de analizador para analizar campos específicos que luego se introducen directamente en los serializadores DRF estándar:
Esto se usa como:
fuente
Si está utilizando ModelViewSet, ¡ya ha terminado! ¡Se encarga de todo por ti! Solo necesita poner el campo en su ModelSerializer y configurarlo
content-type=multipart/form-data;
en su cliente.PERO, como sabes, no puedes enviar archivos en formato json. (cuando el tipo de contenido se establece en application / json en su cliente). A menos que use el formato Base64.
Entonces tienes dos opciones:
ModelViewSet
yModelSerializer
manejar el trabajo y enviar la solicitud usandocontent-type=multipart/form-data;
ModelSerializer
comoBase64ImageField (or) Base64FileField
y dígale a su cliente que codifique el archivoBase64
y establezca elcontent-type=application/json
fuente
modelos.py
serializers.py
views.py
urls.py
settings.py
Envíe una solicitud de publicación a
api/files
con su archivo adjunto a unform-data
campofile
. El archivo se cargará en la/media
carpeta y se agregará un registro de base de datos con la identificación y el nombre del archivo.fuente