在 Django 中,我编写了一个自定义的基于类的验证器并实现了
__eq__
方法,因为它也是为 Django 本身已经实现的验证器完成的。
在这里你可以看到它:
@deconstructible
class FileSizeValidator:
def __init__(self, mb):
self.mb = mb
def __call__(self, value):
limit = self.mb * 1024 * 1024
if value.size > limit:
raise ValidationError('File too big (max. ' + str(self.mb) + ' MiB).')
def __eq__(self, other):
return (
isinstance(other, FileSizeValidator) and
self.mb == other.mb
)
现在,我还为
ImageField
编写了一个自定义类。我想将它用于 upload_to=
模型中的 ImageField
参数。在这里你可以看到我的例子:
@deconstructible
class RandomFileName:
def __init__(self, directory=''):
self.directory = directory
def __call__(self, instance, filename):
return self.directory + ("/" if self.directory else '') + get_random_string(7) + "." + filename.split('.')[-1]
def __eq__(self, other):
return (
isinstance(other, RandomFileName) and
self.directory == other.directory
)
总的来说,我对它很满意,而且看起来效果很好。我只是不知道什么时候我需要
__eq__
方法,想请你解释一下。
这称为运算符重载,在您的示例中,它用于比较两个对象。实现
__eq__()
方法后,您可以比较任何其他对象与您的对象是否相等。
我们现在可以从您的类中创建两个对象:
obj1 = FileSizeValidator(100)
obj2 = FileSizeValidator(200)
并且可以将它们比较为
obj1 == obj2
。
由于我们定义了自定义
__eq__()
,这将比较对象的 class
和 mb
属性的值,以返回 True
或 False
值。如果任何一个条件失败,都会返回False
。
默认情况下,Python 中两个自定义对象的相等运算符会比较对象的
id
值,并且永远不会返回 True
,除非将对象与其自身进行比较。
我认为这与您关心的问题不再相关。但是,你的问题很有趣,现有的答案还不够明确,所以我决定深入研究这个概念。结果如下:
你的问题:Django:我什么时候需要
__eq__
方法?
答案是:
Whenever you want to break the default rule of python to compare two custom objects by redefining your own rule, then you need this strategy.
记住,
方法不仅仅与 Django Validator 相关 仅限班级。它相当适用于您创建的任何 python 类。__eq__
现在让我们深入了解细节。 假设你有一个名为
MyClass
的类,如下所示:
class MyClass:
def __init__(self, age):
self.age = age
现在您初始化此类的三个不同对象:
object1 = MyClass(20)
object2 = MyClass(20)
object3 = MyClass(30)
现在如果我问你,
object1
和object2
一样吗?你的答案是什么?是的,对吗?
是的,你是不正确。不相信我?然后转到您的终端并自行尝试。这些与 python 解释器不同,因为解释器通过对象的内存地址来比较类对象。由于
object1
和object1
的内存地址不同,因此视为不相等。
但我们想打破这个规则。我们希望教育 python 解释器不根据对象的内存地址,而是根据我的指令来比较我的对象。让我们再次重新定义类。
class MyClass:
def __init__(self, age):
self.age = age
def __eq__(self, other):
return isinstance(other, MyClass) and self.age == other.age
现在再次初始化该类的三个对象,
object1 = MyClass(20)
object2 = MyClass(20)
object3 = MyClass(30)
并在终端中比较对象1和对象2
object1 == object2:
这次又回来了
True
。因为,现在解释器不再遵循自己的规则来对自定义对象执行 ==
比较运算符。相反,它在类的 __eq__
方法中发现,如果第二个对象的类与第一个对象的类相同,则比较结果将为 True
isinstance(other, MyClass)
and
第二个对象的年龄与第一个对象的年龄相同物体self.age == other.age
那么,为什么我需要在自定义验证器类中包含
__eq__
方法?
这是因为,当您定义自定义验证类并执行
./manage.py makemigrations
时,django 的迁移框架会创建自定义验证类的对象,对于您的情况,它是 FileSizeValidator
类。当您下次执行 makemigrations
命令时,它会进行比较以检查您是否已更新验证要求(针对您的情况、文件大小)。如果系统发现现有对象和新对象不相等,则会为您更新的验证要求创建新的迁移对象。
那么,我的验证类中是否需要有这个方法?
一点也不。但是,这完全取决于您的要求。如果您认为,您永远不需要更新验证标准,所以不需要。但是如果您认为您可能需要更新它,例如,当前您允许用户上传最大大小为 5mb 的文件,并且迟早您可能需要将其更改为更少或更多,那么您必须重新定义
__eq__
方法。因为 __eq__
是向系统传达有关验证类标准更改的方式。