Wie kann ich einschränken FileField
, dass nur ein bestimmter Dateityp (Video, Audio, PDF usw.) auf elegante Weise serverseitig akzeptiert wird?
django
file-upload
Maroxe
quelle
quelle
Antworten:
Eine sehr einfache Möglichkeit ist die Verwendung eines benutzerdefinierten Validators.
In Ihrer App
validators.py
: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('Unsupported file extension.')
Dann in Ihrem
models.py
:from .validators import validate_file_extension
... und verwenden Sie den Validator für Ihr Formularfeld:
class Document(models.Model): file = models.FileField(upload_to="documents/%Y/%m/%d", validators=[validate_file_extension])
Siehe auch: Wie kann ich Dateitypen beim Hochladen von Dateien für ModelForms mit FileFields einschränken? .
quelle
Django in der Version
1.11
hat einen neu hinzugefügtenFileExtensionValidator
für Modellfelder. Die Dokumentation finden Sie hier: https://docs.djangoproject.com/en/dev/ref/validators/#fileextensionvalidator .Ein Beispiel für die Überprüfung einer Dateierweiterung:
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'])])
Beachten Sie, dass diese Methode nicht sicher ist . Zitat aus Django-Dokumenten:
Es gibt auch neue
validate_image_file_extension
( https://docs.djangoproject.com/de/dev/ref/validators/#validate-image-file-extension ) zum Überprüfen von Bilderweiterungen (mit Pillow).quelle
allowed_extensions
aus irgendeinem Grund nicht hinzugefügt wurde . Verwenden des Django Rest Framework.Es gibt einen Django-Ausschnitt , der dies tut:
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()
quelle
Zuerst. Erstellen Sie eine Datei mit dem Namen formatChecker.py in der App, in der Sie das Modell mit dem FileField haben, das Sie für einen bestimmten Dateityp akzeptieren möchten.
Dies ist Ihr 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
Zweite. Fügen Sie in Ihrer models.py Folgendes hinzu:
from formatChecker import ContentTypeRestrictedFileField
Verwenden Sie dann anstelle von 'FileField' dieses 'ContentTypeRestrictedFileField'.
Beispiel:
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)
Dies sind die Dinge, die Sie tun müssen, wenn Sie nur einen bestimmten Dateityp in FileField akzeptieren möchten.
quelle
Einige Leute haben vorgeschlagen, Python-Magic zu verwenden, um zu überprüfen, ob die Datei tatsächlich von dem Typ ist, den Sie erwarten. Dies kann in die
validator
in der akzeptierten Antwort vorgeschlagene Antwort aufgenommen werden: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.')
In diesem Beispiel wird nur ein PDF überprüft, es können jedoch beliebig viele MIME-Typen und Dateierweiterungen zu den Arrays hinzugefügt werden.
Angenommen, Sie haben das oben Gesagte gespeichert
validators.py
, können Sie dies wie folgt in Ihr Modell integrieren:from myapp.validators import validate_is_pdf class PdfFile(models.Model): file = models.FileField(upload_to='pdfs/', validators=(validate_is_pdf,))
quelle
Sie können das Folgende verwenden, um Dateitypen in Ihrem Formular einzuschränken
file = forms.FileField(widget=forms.FileInput(attrs={'accept':'application/pdf'}))
quelle
Ich denke, Sie wären am besten geeignet, wenn Sie das ExtFileField verwenden würden , das Dominic Rodger in seiner Antwort angegeben hat, und die von Daniel Quinn erwähnte Python-Magie ist der beste Weg. Wenn jemand klug genug ist, um zumindest die Erweiterung zu ändern, werden Sie ihn mit den Headern abfangen.
quelle
Sie können eine Liste der akzeptierten MIME-Typen in den Einstellungen definieren und dann einen Validator definieren, der Python-Magic verwendet, um den MIME-Typ zu erkennen, und ValidationError auslöst, wenn der MIME-Typ nicht akzeptiert wird. Setzen Sie diesen Validator in das Dateiformatfeld.
Das einzige Problem ist, dass der MIME-Typ manchmal Application / Octet-Stream ist, was verschiedenen Dateiformaten entsprechen kann. Hat jemand von Ihnen dieses Problem gelöst?
quelle
Zusätzlich werde ich diese Klasse mit etwas zusätzlichem Verhalten erweitern.
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)
Wenn wir eine Instanz mit param accept = ".pdf, .txt" erstellen, werden im Popup mit der Dateistruktur als Standard standardmäßig Dateien mit übergebener Erweiterung angezeigt.
quelle
Nachdem ich die akzeptierte Antwort überprüft hatte, beschloss ich, einen Tipp basierend auf der Django-Dokumentation zu teilen. Es gibt bereits einen Validator zur Validierung der Dateierweiterung. Sie müssen Ihre eigene benutzerdefinierte Funktion nicht neu schreiben, um zu überprüfen, ob Ihre Dateierweiterung zulässig ist oder nicht.
https://docs.djangoproject.com/de/3.0/ref/validators/#fileextensionvalidator
quelle