¿Cómo puedo restringir FileField
para aceptar solo un cierto tipo de archivo (video, audio, pdf, etc.) de una manera elegante, en el lado del servidor?Solo acepta cierto tipo de archivo en FileField, lado del servidor
Respuesta
Una manera muy fácil es usar un validador personalizado.
En validators.py
de su aplicación:
def validate_file_extension(value):
import os
from django.core.exceptions import ValidationError
ext = os.path.splitext(value.name)[1] # [0] returns path+filename
valid_extensions = ['.pdf', '.doc', '.docx', '.jpg', '.png', '.xlsx', '.xls']
if not ext.lower() in valid_extensions:
raise ValidationError(u'Unsupported file extension.')
Luego, en su models.py
:
from .validators import validate_file_extension
... y utilizar el validador para el campo de formulario:
class Document(models.Model):
file = models.FileField(upload_to="documents/%Y/%m/%d", validators=[validate_file_extension])
Ver también: How to limit file types on file uploads for ModelForms with FileFields?.
Esto debería ser aceptado como respuesta. ¡Muchas gracias! – vabada
@dabad utilizando solo la extensión no es bueno para la validación de archivos, este tipo de respuestas crea lagunas de seguridad; Por favor, chicos que vean estas respuestas también verifiquen CVE relacionado a diferentes formatos y validadores, tome el caso de pillow/PIL por ejemplo: O –
Hay una Django snippet que hace esto:
import os
from django import forms
class ExtFileField(forms.FileField):
"""
Same as forms.FileField, but you can specify a file extension whitelist.
>>> from django.core.files.uploadedfile import SimpleUploadedFile
>>>
>>> t = ExtFileField(ext_whitelist=(".pdf", ".txt"))
>>>
>>> t.clean(SimpleUploadedFile('filename.pdf', 'Some File Content'))
>>> t.clean(SimpleUploadedFile('filename.txt', 'Some File Content'))
>>>
>>> t.clean(SimpleUploadedFile('filename.exe', 'Some File Content'))
Traceback (most recent call last):
...
ValidationError: [u'Not allowed filetype!']
"""
def __init__(self, *args, **kwargs):
ext_whitelist = kwargs.pop("ext_whitelist")
self.ext_whitelist = [i.lower() for i in ext_whitelist]
super(ExtFileField, self).__init__(*args, **kwargs)
def clean(self, *args, **kwargs):
data = super(ExtFileField, self).clean(*args, **kwargs)
filename = data.name
ext = os.path.splitext(filename)[1]
ext = ext.lower()
if ext not in self.ext_whitelist:
raise forms.ValidationError("Not allowed filetype!")
#-------------------------------------------------------------------------
if __name__ == "__main__":
import doctest, datetime
doctest.testmod()
Este es un filtro basado en la extensión, que no es confiable en absoluto. Estaba pensando en analizar el archivo después de subir los acabados. – maroxe
@maroxe ¿Encontró una solución a esto? Solo tengo el mismo problema para determinar si los archivos son audiofiles o no. – marue
Pruebe este enlace: http://nemesisdesign.net/blog/coding/django-filefield-content-type-size-validation/ – PhoebeB
Primera. Cree un archivo llamado formatChecker.py dentro de la aplicación donde tiene el modelo que tiene FileField y desea aceptar un determinado tipo de archivo.
Esta es su formatChecker.py:
from django.db.models import FileField
from django.forms import forms
from django.template.defaultfilters import filesizeformat
from django.utils.translation import ugettext_lazy as _
class ContentTypeRestrictedFileField(FileField):
"""
Same as FileField, but you can specify:
* content_types - list containing allowed content_types. Example: ['application/pdf', 'image/jpeg']
* max_upload_size - a number indicating the maximum file size allowed for upload.
2.5MB - 2621440
5MB - 5242880
10MB - 10485760
20MB - 20971520
50MB - 5242880
100MB 104857600
250MB - 214958080
500MB - 429916160
"""
def __init__(self, *args, **kwargs):
self.content_types = kwargs.pop("content_types")
self.max_upload_size = kwargs.pop("max_upload_size")
super(ContentTypeRestrictedFileField, self).__init__(*args, **kwargs)
def clean(self, *args, **kwargs):
data = super(ContentTypeRestrictedFileField, self).clean(*args, **kwargs)
file = data.file
try:
content_type = file.content_type
if content_type in self.content_types:
if file._size > self.max_upload_size:
raise forms.ValidationError(_('Please keep filesize under %s. Current filesize %s') % (filesizeformat(self.max_upload_size), filesizeformat(file._size)))
else:
raise forms.ValidationError(_('Filetype not supported.'))
except AttributeError:
pass
return data
Segundo. En su models.py, añadir lo siguiente:
from formatChecker import ContentTypeRestrictedFileField
A continuación, en lugar de utilizar 'FileField', utilizar este 'ContentTypeRestrictedFileField'.
Ejemplo:
class Stuff(models.Model):
title = models.CharField(max_length=245)
handout = ContentTypeRestrictedFileField(upload_to='uploads/', content_types=['video/x-msvideo', 'application/pdf', 'video/mp4', 'audio/mpeg', ],max_upload_size=5242880,blank=True, null=True)
Esas son las cosas que tiene que cuando se quiere aceptar sólo un determinado tipo de archivo en FileField.
content-type es fácil de engañar –
Agregando esta línea antes de la super llamada: self.widget = ClearableFileInput (attrs = {' accept ':', '. join (self.content_types)}) solo hará que los tipos de contenido aceptados sean seleccionables en la ventana modal. – laffuste
@laffuste Después de haber enviado su comentario votando arriba, esto no parece funcionar en Mac (es decir, los archivos pueden seleccionarse). Sin embargo, no han probado en Windows. – Erve1879
Creo que sería más adecuado usar el ExtFileField que Dominic Rodger especificó en su respuesta y python-magic que Daniel Quinn mencionó es la mejor manera de hacerlo. Si alguien es lo suficientemente inteligente como para cambiar la extensión, al menos los atrapará con los encabezados.
Dado que ha determinado que este es el mejor método, ¿por qué no publicar un código para demostrarlo al resto de nosotros? – Thismatters
Además extenderé esta clase con algún comportamiento adicional.
class ContentTypeRestrictedFileField(forms.FileField):
...
widget = None
...
def __init__(self, *args, **kwargs):
...
self.widget = forms.ClearableFileInput(attrs={'accept':kwargs.pop('accept', None)})
super(ContentTypeRestrictedFileField, self).__init__(*args, **kwargs)
Cuando creamos instancia con el parámetro accept = "pdf, txt", en la ventana emergente con la estructura de archivos por defecto veremos los archivos con extensión pasado.
Puede definir una lista de tipos de mime aceptados en la configuración y luego definir un validador que use python-magic para detectar el tipo mime y provoca ValidationError si no se acepta el tipo mime. Establezca ese validador en el campo de formulario de archivo.
El único problema es que a veces el tipo mime es application/octet-stream, que podría corresponder a diferentes formatos de archivo. ¿Alguien de ustedes superó este problema?
Django en la versión 1.11
tiene un recién agregado FileExtensionValidator
para los campos del modelo, el documento está aquí: https://docs.djangoproject.com/en/dev/ref/validators/#fileextensionvalidator.
Un ejemplo de cómo validar una extensión de archivo:
from django.core.validators import FileExtensionValidator
from django.db import models
class MyModel(models.Model):
pdf_file= models.FileField(upload_to='foo/', validators=[FileExtensionValidator(allowed_extensions=['pdf'])])
Tenga en cuenta que este método es no es seguro. Cita de documentos de Django:
No confíe en la validación de la extensión de archivo para determinar el tipo de un archivo . Los archivos se pueden renombrar para tener cualquier extensión sin importar qué datos contienen .
También es nueva validate_image_file_extension
(https://docs.djangoproject.com/en/dev/ref/validators/#validate-image-file-extension) para la validación de las extensiones de imagen (que usa la almohadilla).
Usted puede utilizar el siguiente para restringir los tipos de archivos en su Formulario
file = forms.FileField(widget=forms.FileInput(attrs={'accept':'application/pdf'}))
Algunas personas han sugerido el uso de python-magic para validar que el archivo es en realidad del tipo que está esperando recibir. Esto puede ser incorporado en el validator
se sugiere en la respuesta aceptada:
import os
import magic
from django.core.exceptions import ValidationError
def validate_is_pdf(file):
valid_mime_types = ['application/pdf']
file_mime_type = magic.from_buffer(file.read(1024), mime=True)
if file_mime_type not in valid_mime_types:
raise ValidationError('Unsupported file type.')
valid_file_extensions = ['.pdf']
ext = os.path.splitext(file.name)[1]
if ext.lower() not in valid_file_extensions:
raise ValidationError('Unacceptable file extension.')
Este ejemplo sólo valida un pdf, pero cualquier número de tipos MIME y extensiones de archivo se puede agregar a las matrices.
Asumiendo que salvó a la anterior en validators.py
puede incorporar esto en su modelo de este modo:
from myapp.validators import validate_is_pdf
class PdfFile(models.Model):
file = models.FileField(upload_to='pdfs/', validators=(validate_is_pdf,))
- 1. Lectura del archivo del lado del servidor con Javascript
- 2. Exploración de archivos del lado del servidor
- 3. Cookies solo del lado del cliente
- 4. HTML5 - lado del servidor
- 5. Análisis del lado del servidor
- 6. lado del servidor JavaScript - general
- 7. Método del lado del servidor y del lado del cliente
- 8. Ruby: del lado del cliente o del lado del servidor?
- 9. Comprobación del lado del servidor frente al lado del agente
- 10. Web Charting, lado del servidor o del lado del cliente?
- 11. django filefield return filename filename solo en la plantilla
- 12. GWT I18N en el lado del servidor
- 13. Línea de comando del lado del servidor
- 14. Escaneo de virus del lado del servidor
- 15. Renderización animación HTML5 del lado del servidor?
- 16. ¿Cómo funciona el lado del servidor GZipping?
- 17. Paginación: ¿lado del servidor o lado del cliente?
- 18. ASP.NET Validación lado del servidor
- 19. lado del servidor MVC + lado del cliente MVC
- 20. ¿Cómo ignoro cierto tipo de archivo en cierto directorio y su subdirectorio en Git?
- 21. Exploración de virus del lado del servidor en un archivo para Windows
- 22. Rendering HTML + Javascript del lado del servidor
- 23. autocompletar aplicación del lado del servidor
- 24. Crear validación combinada del lado del cliente y del lado del servidor en Symfony2
- 25. Validación de datos del lado del servidor en Express + node.js
- 26. Uso del certificado Wcf SSl sobre Tcp sin certificado de cliente (solo del lado del servidor)
- 27. Validación de entrada de usuario, del lado del cliente o del lado del servidor? [PHP/JS]
- 28. CSS en el lado del servidor?
- 29. ASP.NET equivalente del lado del servidor incluye
- 30. marco javascript del lado del servidor
Para obtener el diálogo abierto para restringir los archivos a ciertos tipos de cliente, [ver esta pregunta] (http: //stackoverflow.com/a/40847649/247696). – Flimm