Django - Validación del tipo de archivo cargado

Necesito validar el tipo de archivo del archivo cargado y debería permitir solo archivos pdf, prueba simple y MS word. Aquí está mi modelo y el formulario con función de validación. Pero puedo cargar archivos incluso sin la extensión.

class Section(models.Model):
    content = models.FileField(upload_to="documents")

class SectionForm(forms.ModelForm):
    class Meta:
        model = Section
    FILE_EXT_WHITELIST = ['pdf','text','msword']

    def clean_content(self):
        content = self.cleaned_data['content']
        if content:
            file_type = content.content_type.split('/')[0]
            print file_type
            if len(content.name.split('.')) == 1:
                raise forms.ValidationError("File type is not supported.")
            if content.name.split('.')[-1] in self.FILE_EXT_WHITELIST:
                return content
            else:
                raise forms.ValidationError("Only '.txt' and '.pdf' files are allowed.")

Aquí está la vista,

def section_update(request, object_id):
    section = models.Section.objects.get(pk=object_id)
    if 'content' in request.FILES:
            if request.FILES['content'].name.split('.')[-1] == "pdf":
                content_file = ContentFile(request.FILES['content'].read())
                content_type = "pdf"
                section.content.save("test"+'.'+content_type , content_file)
                section.save()

En mi opinión, solo estoy guardando el archivo desde el request.FILE. Pensé que mientras save() llamará a clean_content y hará la validación del tipo de contenido. Supongo que clean_content no requiere en absoluto validación.

preguntado el 31 de julio de 12 a las 14:07

3 Respuestas

Su enfoque no funcionará: como atacante, simplemente podría falsificar el encabezado HTML para enviarle cualquier cosa con el tipo mime text/plain.

La solución correcta es usar una herramienta como file(1) en Unix para examinar el contenido del archivo y determinar de qué se trata. Tenga en cuenta que no hay una buena manera de saber si algo es realmente texto sin formato. Si el archivo se guarda en Unicode de 16 bits, el "texto sin formato" puede contener incluso 0 bytes.

Consulte esta pregunta para conocer las opciones de cómo hacer esto: ¿Cómo encontrar el tipo de mime de un archivo en Python?

contestado el 23 de mayo de 17 a las 11:05

Sí estoy de acuerdo con usted. Se insiste en "confiar pero verificar" en los documentos de Django. Pero necesito subir el forms.ValidationError para un archivo inválido como sea que se verifique. - Babu

NO, def clean_content no es en absoluto llamando. Supongo que no podemos mezclar el modelo y su forma de generar errores de validación. Verificaré el archivo como sugirió y lo redirigiré a una vista de error si falla la validación. Gracias. - Babu

ah En ese caso, su pregunta debería ser "¿Por qué nunca se llama a clean_content()?" Sugiero abrir una nueva pregunta. - Aarón Digulla

Puedes usar pitón-magia

import magic
magic.from_file('/my/file.jpg', mime=True)
# image/jpeg

Respondido el 06 de enero de 19 a las 12:01

Esta es una pregunta antigua, pero para los usuarios posteriores, la pregunta principal como se menciona en los comentarios es por qué no ocurre la validación de campo, y como se describe en la documentación de django, la validación del campo se ejecuta cuando llamas a is_valid(). Por lo tanto, debe usar algo como lo siguiente a la vista para activar la validación de campo:

section = models.Section.objects.get(pk=object_id)    
if request.method == 'POST':    
   form = SectionForm(request.POST, request.FILES)
   if form.is_valid:
      do_something_with_form

La validación del formulario ocurre cuando se limpian los datos. Si desea personalizar este proceso, hay varios lugares para realizar cambios, cada uno con un propósito diferente. Se ejecutan tres tipos de métodos de limpieza durante el procesamiento del formulario. Estos normalmente se ejecutan cuando llama al método is_valid() en un formulario

Respondido 15 Abr '21, 15:04

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.