代码之家  ›  专栏  ›  技术社区  ›  spraff

为什么克隆floatfield的这个子类(添加了验证器)会引发异常?

  •  1
  • spraff  · 技术社区  · 6 年前

    我是python和django的新手。

    我希望我的模型有范围验证的浮动。从 this answer 我写的是:

    class FloatRangeField (FloatField):
        """A FloatField constrained to a given range."""
    
        def __init__ (self, minimum, maximum, **kwargs):
    
            minmax = [MinValueValidator (minimum), MaxValueValidator (maximum)]
    
            print ("\n\t\tFloatRangeField({},{})".format(minimum,maximum)) # (A)
            FloatField.__init__ (self, validators = minmax, **kwargs)
            print ("\t\tFINISHED\n")
    

    这导致了 python3 manage.py migrate ,我把范围缩小到 clone() 打电话。演示:

    print ("HERE 1")
    tmp1 = FloatRangeField (10, 20)
    print ("HERE 2")
    tmp2 = FloatRangeField (10, 20)
    print ("HERE 3")
    tmp3 = tmp1.clone ()      # (B)
    print ("HERE 4")
    

    它从第行引发异常 # (B) . 奇怪的是,当这种情况发生时 # (A) 印刷的。输出如下:

    HERE 1
    
                    FloatRangeField(10,20)
                    FINISHED
    
    HERE 2
    
                    FloatRangeField(10,20)
                    FINISHED
    
    HERE 3
    Traceback (most recent call last):
      File "manage.py", line 15, in <module>
        execute_from_command_line(sys.argv)
      File "/usr/local/lib/python3.5/dist-packages/django/core/management/__init__.py", line 371, in execute_from_command_line
        utility.execute()
    
    [...snip...]
    
        tmp3 = tmp1.clone ()
      File "/usr/local/lib/python3.5/dist-packages/django/db/models/fields/__init__.py", line 470, in clone
        return self.__class__(*args, **kwargs)
    TypeError: __init__() missing 2 required positional arguments: 'minimum' and 'maximum'
    

    也没有印刷出来的怪事 (a) ,这是 和我看到的错误一样 migrate . 如果我把 tmp1=... 塞东西然后跑 迁移 ,回溯如下

    Traceback (most recent call last):
      File "/usr/local/lib/python3.5/dist-packages/django/db/migrations/state.py", line 411, in from_model
        fields.append((name, field.clone()))
      File "/usr/local/lib/python3.5/dist-packages/django/db/models/fields/__init__.py", line 470, in clone
        return self.__class__(*args, **kwargs)
    
    [...snip...]
    
        FloatField.__init__ (self, validators = minmax, **kwargs)
    TypeError: __init__() got multiple values for keyword argument 'validators'
    

    为什么会中断,我应该如何实现 FloatRangeField 以便封装最小/最大验证器的拥有?

    1 回复  |  直到 6 年前
        1
  •  2
  •   willeM_ Van Onsem    6 年前

    就像写在 documentation on custom model fields :

    如果添加新的关键字参数,则需要编写代码将其值放入 kwargs 你自己(…)

    所以你也应该增加一个解构主义者。这是必需的,例如要在迁移文件中表示此字段:

    class FloatRangeField (FloatField):
        """A FloatField constrained to a given range."""
    
        def __init__ (self, minimum, maximum, **kwargs):
            self.minimum = minimum
            self.maximum = maximum
            minmax = [MinValueValidator (minimum), MaxValueValidator (maximum)]
            FloatField.__init__ (self, validators = minmax, **kwargs)
    
        def deconstruct(self):
            result = __, __, __, kwargs = super(FloatRangeField, self).deconstruct()
            kwargs['minimum'] = self.minimum
            kwargs['minimum'] = self.maximum
            del kwargs['validators']
            return result

    注意,你最好不要使用 validators = minmax 作为参数,因为这将意味着如果用户将使用 validator 你的参数 FloatRangeField 构造函数将出现参数冲突。

    例如,可以 追加 我们的 minmax 已存在的验证器的验证器,然后当我们想解构它时,从验证程序中弹出这些回溯符:

    class FloatRangeField (FloatField):
        """A FloatField constrained to a given range."""
    
        def __init__ (self, minimum, maximum, **kwargs):
            self.minimum = minimum
            self.maximum = maximum
            old_validators = kwargs.get('validators', [])
            minmax = [MinValueValidator (minimum), MaxValueValidator (maximum)]
            kwargs['validators'] = minmax + old_validators
            FloatField.__init__ (self, **kwargs)
    
    
        def deconstruct(self):
            result = __, __, __, kwargs = super(FloatRangeField, self).deconstruct()
            kwargs['minimum'] = self.minimum
            kwargs['minimum'] = self.maximum
            kwargs['validators'] = kwargs['validators'][2:]
            return result

    所以我们在这里 deconstruct(..) 函数,删除前两个验证器(我们在 __init__(..) 函数)。