我有一个可以让人们上传文件的应用程序,表示为UploadedFiles。但是,我要确保用户仅上传xml文件。我知道我可以使用进行此操作magic,但是我不知道将检查放在何处-据我所知,clean由于文件在clean运行时尚未上传,因此无法将其放在函数中。
UploadedFiles
magic
这是UploadedFile模型:
UploadedFile
class UploadedFile(models.Model): """This represents a file that has been uploaded to the server.""" STATE_UPLOADED = 0 STATE_ANNOTATED = 1 STATE_PROCESSING = 2 STATE_PROCESSED = 4 STATES = ( (STATE_UPLOADED, "Uploaded"), (STATE_ANNOTATED, "Annotated"), (STATE_PROCESSING, "Processing"), (STATE_PROCESSED, "Processed"), ) status = models.SmallIntegerField(choices=STATES, default=0, blank=True, null=True) file = models.FileField(upload_to=settings.XML_ROOT) project = models.ForeignKey(Project) def __unicode__(self): return self.file.name def name(self): return os.path.basename(self.file.name) def save(self, *args, **kwargs): if not self.status: self.status = self.STATE_UPLOADED super(UploadedFile, self).save(*args, **kwargs) def delete(self, *args, **kwargs): os.remove(self.file.path) self.file.delete(False) super(UploadedFile, self).delete(*args, **kwargs) def get_absolute_url(self): return u'/upload/projects/%d' % self.id def clean(self): if not "XML" in magic.from_file(self.file.url): raise ValidationError(u'Not an xml file.') class UploadedFileForm(forms.ModelForm): class Meta: model = UploadedFile exclude = ('project',)
对于后代:解决方案是使用read方法并将其传递给magic.from_buffer。
magic.from_buffer
class UploadedFileForm(ModelForm): def clean_file(self): file = self.cleaned_data.get("file", False) filetype = magic.from_buffer(file.read()) if not "XML" in filetype: raise ValidationError("File is not XML.") return file class Meta: model = models.UploadedFile exclude = ('project',)
验证文件是一个常见的挑战,因此我想使用一个验证器:
import magic from django.utils.deconstruct import deconstructible from django.template.defaultfilters import filesizeformat @deconstructible class FileValidator(object): error_messages = { 'max_size': ("Ensure this file size is not greater than %(max_size)s." " Your file size is %(size)s."), 'min_size': ("Ensure this file size is not less than %(min_size)s. " "Your file size is %(size)s."), 'content_type': "Files of type %(content_type)s are not supported.", } def __init__(self, max_size=None, min_size=None, content_types=()): self.max_size = max_size self.min_size = min_size self.content_types = content_types def __call__(self, data): if self.max_size is not None and data.size > self.max_size: params = { 'max_size': filesizeformat(self.max_size), 'size': filesizeformat(data.size), } raise ValidationError(self.error_messages['max_size'], 'max_size', params) if self.min_size is not None and data.size < self.min_size: params = { 'min_size': filesizeformat(self.min_size), 'size': filesizeformat(data.size) } raise ValidationError(self.error_messages['min_size'], 'min_size', params) if self.content_types: content_type = magic.from_buffer(data.read(), mime=True) data.seek(0) if content_type not in self.content_types: params = { 'content_type': content_type } raise ValidationError(self.error_messages['content_type'], 'content_type', params) def __eq__(self, other): return ( isinstance(other, FileValidator) and self.max_size == other.max_size and self.min_size == other.min_size and self.content_types == other.content_types )
然后,您可以FileValidator在中model.FileField或forms.FileField按以下方式使用:
validate_file = FileValidator(max_size=1024 * 100, content_types=('application/xml',)) file = models.FileField(upload_to=settings.XML_ROOT, validators=[validate_file])