由于验证器,Django 1.8 makemigrations每次都会生成重复的迁移

时间:2018-05-21 01:32:32

标签: django django-migrations django-validation

我有一个模型,其中包含一个带有以下验证器的字段:

@deconstructible
class FileValidator(object):
    """
    Validator for files, checking the size, extension and mimetype.
    Initialization parameters:
        allowed_extensions: iterable with allowed file extensions
            ie. ('txt', 'doc')
        allowd_mimetypes: iterable with allowed mimetypes
            ie. ('image/png', )
        min_size: minimum number of bytes allowed
            ie. 100
        max_size: maximum number of bytes allowed
            ie. 24*1024*1024 for 24 MB
    Usage example::
        MyModel(models.Model):
            myfile = FileField(validators=FileValidator(max_size=24*1024*1024), ...)

    See https://gist.github.com/jrosebr1/2140738 (improved)
    """

    extension_message = _("Extension '%(extension)s' not allowed. Allowed extensions are: '%(allowed_extensions)s.'")
    mime_message = _("MIME type '%(mimetype)s' is not valid. Allowed types are: %(allowed_mimetypes)s.")
    min_size_message = _('The current file %(size)s, which is too small. The minumum file size is %(allowed_size)s.')
    max_size_message = _('The current file %(size)s, which is too large. The maximum file size is %(allowed_size)s.')

    def __init__(self, *args, **kwargs):
        self.allowed_extensions = kwargs.pop('allowed_extensions', None)
        self.allowed_mimetypes = kwargs.pop('allowed_mimetypes', None)
        self.min_size = kwargs.pop('min_size', 0)
        self.max_size = kwargs.pop('max_size', DEFAULT_FILE_MAX_SIZE)

    def __call__(self, value):
        """
        Check the extension, content type and file size.
        """

        # Check the extension
        ext = splitext(value.name)[1][1:].lower()
        if self.allowed_extensions and not ext in self.allowed_extensions:
            message = self.extension_message % {
                'extension': ext,
                'allowed_extensions': ', '.join(self.allowed_extensions)
            }

            raise ValidationError(message)

        # Check the content type
        # mimetype = mimetypes.guess_type(value.name)[0] # XXX Alternative guessing way, unsure
        mimetype = magic.from_buffer(value.read(1024), mime=True)
        if self.allowed_mimetypes and not mimetype in self.allowed_mimetypes:
            message = self.mime_message % {
                'mimetype': mimetype,
                'allowed_mimetypes': ', '.join(self.allowed_mimetypes)
            }

            raise ValidationError(message)

        # Check the file size
        filesize = len(value)
        if self.max_size and filesize > self.max_size:
            message = self.max_size_message % {
                'size': filesizeformat(filesize),
                'allowed_size': filesizeformat(self.max_size)
            }

            raise ValidationError(message)

        elif filesize < self.min_size:
            message = self.min_size_message % {
                'size': filesizeformat(filesize),
                'allowed_size': filesizeformat(self.min_size)
            }

            raise ValidationError(message)

验证器本身就是

./manage.py makemigrations app1

每次我运行0003_auto_20180521_0325.py: - Alter field xxx on yyy

__eq__

每次都会生成一个新的迁移,它总是做同样的事情(改变字段)

如果我注释掉我的验证器,则此行为会停止,并且makemigrations会显示&#34;未检测到更改&#34;消息。

出了什么问题?我该如何避免这种行为?

编辑:关注@ benjamin的回答,这是完整的代码,包括修复。 (# -*- coding: utf-8 -*- import magic from os.path import splitext from django.core.exceptions import ValidationError from django.utils.deconstruct import deconstructible from django.utils.translation import gettext_lazy as _ from django.template.defaultfilters import filesizeformat DEFAULT_FILE_MAX_SIZE = 10 * 1024 * 1024 # 10Mo # Photo, like profile picture # Only allow web-friendly extensions/mime types, since they'll be displayed on web pages # TODO Size is huge, should be optimised ALLOWED_PHOTO_EXT = [ 'jpg', 'jpeg', 'png', ] ALLOWED_PHOTO_MIME_TYPES = [ 'image/jpeg', 'image/pjpeg', 'image/png', 'image/x-png', ] ALLOWED_PHOTO_MAX_SIZE = 10 * 1024 * 1024 # 10Mo # Any document # Allow a wide range of extensions and mime types # TODO Size is huge, should be optimised ALLOWED_DOCUMENT_EXT = [ 'jpg', 'jpeg', 'png', 'tif', 'bmp', 'pdf', 'doc', 'dot', 'docx', 'dotx', 'xls', 'xlt', 'xla', 'xlsx', 'xltx', 'pptx', 'potx', 'ppsx', ] ALLOWED_DOCUMENT_MIME_TYPES = [ 'image/jpeg', 'image/pjpeg', 'image/png', 'image/x-png', 'image/tiff', 'image/bmp', 'application/pdf', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/zip', # XXX PPTX can be detected as ZIP for some reasons ] ALLOWED_DOCUMENT_MAX_SIZE = 10 * 1024 * 1024 # 10Mo # Any document sent to SMoney, which have their own rules and limitations # Allow a wide range of extensions and mime types # TODO Size is huge, should be optimised ALLOWED_DOCUMENT_SMONEY_EXT = [ 'jpg', 'jpeg', 'png', 'tif', 'bmp', 'pdf', ] ALLOWED_DOCUMENT_SMONEY_MIME_TYPES = [ 'image/jpeg', 'image/pjpeg', 'image/png', 'image/x-png', 'image/tiff', 'image/bmp', 'application/pdf', ] ALLOWED_DOCUMENT_SMONEY_MAX_SIZE = 3 * 1024 * 1024 # 3Mo @deconstructible class FileValidator(object): """ Validator for files, checking the size, extension and mimetype. Initialization parameters: allowed_extensions: iterable with allowed file extensions ie. ('txt', 'doc') allowd_mimetypes: iterable with allowed mimetypes ie. ('image/png', ) min_size: minimum number of bytes allowed ie. 100 max_size: maximum number of bytes allowed ie. 24*1024*1024 for 24 MB Usage example:: MyModel(models.Model): myfile = FileField(validators=FileValidator(max_size=24*1024*1024), ...) See https://gist.github.com/jrosebr1/2140738 (improved) """ extension_message = _("Extension '%(extension)s' not allowed. Allowed extensions are: '%(allowed_extensions)s.'") mime_message = _("MIME type '%(mimetype)s' is not valid. Allowed types are: %(allowed_mimetypes)s.") min_size_message = _('The current file %(size)s, which is too small. The minumum file size is %(allowed_size)s.') max_size_message = _('The current file %(size)s, which is too large. The maximum file size is %(allowed_size)s.') def __init__(self, *args, **kwargs): self.allowed_extensions = kwargs.pop('allowed_extensions', None) self.allowed_mimetypes = kwargs.pop('allowed_mimetypes', None) self.min_size = kwargs.pop('min_size', 0) self.max_size = kwargs.pop('max_size', DEFAULT_FILE_MAX_SIZE) def __call__(self, value): """ Check the extension, content type and file size. """ # Check the extension ext = splitext(value.name)[1][1:].lower() if self.allowed_extensions and not ext in self.allowed_extensions: message = self.extension_message % { 'extension': ext, 'allowed_extensions': ', '.join(self.allowed_extensions) } raise ValidationError(message) # Check the content type # mimetype = mimetypes.guess_type(value.name)[0] # XXX Alternative guessing way, unsure mimetype = magic.from_buffer(value.read(1024), mime=True) if self.allowed_mimetypes and not mimetype in self.allowed_mimetypes: message = self.mime_message % { 'mimetype': mimetype, 'allowed_mimetypes': ', '.join(self.allowed_mimetypes) } raise ValidationError(message) # Check the file size filesize = len(value) if self.max_size and filesize > self.max_size: message = self.max_size_message % { 'size': filesizeformat(filesize), 'allowed_size': filesizeformat(self.max_size) } raise ValidationError(message) elif filesize < self.min_size: message = self.min_size_message % { 'size': filesizeformat(filesize), 'allowed_size': filesizeformat(self.min_size) } raise ValidationError(message) def __eq__(self, other): return ( isinstance(other, self.__class__) and self.allowed_extensions == other.allowed_extensions and self.allowed_mimetypes == other.allowed_mimetypes and self.min_size == self.min_size and self.max_size == self.max_size ) 功能)

<template>
 <div>
  <vue-c3 :handler="handler"></vue-c3>
 </div>
</template>

<script>
 import Vue from 'vue'
 import VueC3 from 'vue-c3'

 export default {
  name: ...,
  components: {
   VueC3
  },

  data () {
    return {
    handler: new Vue()
   }
  }
}
</script>

2 个答案:

答案 0 :(得分:1)

我愿意猜测这是因为验证器类中缺少__eq__方法。默认比较中的某些内容看起来并不等于&#39;基于其__dict__以相同方式初始化的两个实例。尝试添加一个明确的:

def __eq__(self, other):
    return (isinstance(other, self.__class__) and 
            self.allowed_extensions == other.allowed_extensions and
            self.allowed_mimetypes == other.allowed_mimetypes and
            self.min_size == self.min_size and
            self.max_size == self.max_size
    )

答案 1 :(得分:0)

/app_name/migrations

删除除 __ init __。py

以外的所有.py文件
python manage.py makemigrations
python manage.py migrate

如果这不起作用,那么你可以尝试我已经完成的事情

在视图中我检查图像是否有效

def check_image(request):

    if len(request.FILES) != 0:

        image = request.FILES['image'] # <input type="file" name="image" ....>
        ext = os.path.splitext(image.name)[1]

        if ext in ['.jpg', '.jpeg', '.png', '.gif']:
            # file is image
            x=0
        else:
            # file is not image
            y=0

    return HttpResponseRedirect('/')