Django比较模型实例的相等性

oro*_*aki 38 django django-models

我理解,在单例情况下,您可以执行以下操作:

spam == eggs
Run Code Online (Sandbox Code Playgroud)

如果spameggs是具有所有相同属性值的同一个类的实例,它将返回True.在Django模型中,这是很自然的,因为模型的两个独立实例将不会相同,除非它们具有相同的.pk值.

这样做的问题是,如果对实例的引用具有已经由中间件在某个地方更新并且尚未保存的属性,并且您正在尝试将其添加到另一个变量中,该变量持有对该实例的引用.同样的模型,它False当然会返回,因为它们对某些属性有不同的值.显然我不需要像单身人士这样的东西,但我想知道是否有一些官方的Djangonic(ha,一个新词)方法来检查这个,或者我是否应该只检查.pk值是否相同:

spam.pk == eggs.pk
Run Code Online (Sandbox Code Playgroud)

我很抱歉,如果这是浪费时间,但似乎可能有一种方法可以做到这一点,而我错过的一些事情,如果我找不到它,我会后悔的.

更新(02-27-2015)

你应该忽略这个问题的第一部分,因为你不应该将单身人士与之比较==,而是与之比较is.单身者真的与这个问题无关.

小智 73

来自django文档:

要比较两个模型实例,只需使用标准的Python比较运算符,双等号:==.在幕后,比较两个模型的主键值.

  • 如果您查询同一模型两次然后更新一个但不更新另一个,该怎么办?比较主键会导致相等,而情况并非如此. (7认同)
  • 我想听听对此的回应 - 我的直觉是说在任何情况下都不应该更新主键,所以即使其中一个实例改变了主键也不会,而且`==`检查将按预期工作. (2认同)
  • 这个答案根本就是错误的。通过比较PK来平等是太天真了。最简单、更正确的比较方法是导出/序列化两个实例并比较结果。即 obj1.to_dict() == obj2.to_dict() (2认同)

Anu*_*yal 17

spam.pk == eggs.pk 这是一个很好的方法.

您可以添加__eq__ 到您的模型但我会避免这种情况,因为它会让人感到困惑,因为它==可能意味着在不同的环境中有不同的东西,例如我可能想要==表示内容相同,ID可能不同,所以再次最好的方法是

spam.pk == eggs.pk
Run Code Online (Sandbox Code Playgroud)

编辑:btw在django 1.0.2模型类中定义__eq__

def __eq__(self, other):
    return isinstance(other, self.__class__) and self._get_pk_val() == other._get_pk_val() 
Run Code Online (Sandbox Code Playgroud)

这似乎与spam.pk == eggs.pk相同,因为pk是使用的属性_get_pk_val 我不明白为什么spam == eggs不工作?

  • 有趣.问题是如果两个实例都没有主键,它将始终返回true.因此,如果您有5个模型实例要相互测试而没有保存,则它们可能都不同,但它们会将`__eq__`测试为"True". (4认同)

Kev*_*nry 8

从Django 2.1.2开始,模型实例相等的源代码如下:

def __eq__(self, other):
    if not isinstance(other, Model):
        return False
    if self._meta.concrete_model != other._meta.concrete_model:
        return False
    my_pk = self.pk
    if my_pk is None:
        return self is other
    return my_pk == other.pk
Run Code Online (Sandbox Code Playgroud)

也就是说,如果来自相同的数据库表并且具有相同的主键,则两个模型实例是相等的.如果任何一个主键是None它们只是相同,如果它们是同一个对象.

(所以回到OP的问题,只需比较实例就可以了.)


pio*_*otr 5

您可以定义Class' __eq__方法来解决该行为:

http://docs.python.org/reference/datamodel.html