Django比较模型实例的相等性

时间:2010-03-25 05:48:12

标签: django django-models

据我所知,在单例情况下,您可以执行以下操作:

spam == eggs

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

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

spam.pk == eggs.pk

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

更新(02-27-2015)

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

8 个答案:

答案 0 :(得分:69)

来自django documentation

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

答案 1 :(得分:17)

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

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

spam.pk == eggs.pk

编辑: btw in django 1.0.2模型类将__eq__定义为

def __eq__(self, other):
    return isinstance(other, self.__class__) and self._get_pk_val() == other._get_pk_val() 

似乎与spam.pk == eggs.pk相同pk是使用_get_pk_val的属性 所以我不明白为什么spam == eggs不起作用?

答案 2 :(得分:8)

从Django 2.2.1开始,模型实例相等的源代码是this

$count = $result->fetch_array(MYSQLI_NUM);

也就是说,如果来自同一个数据库表并具有相同的主键,则两个模型实例是相等的。如果主键为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 ,则只要它们是同一个对象,它们才会相等。

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

答案 3 :(得分:5)

您可以定义类'__eq__方法来更改行为:

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

答案 4 :(得分:4)

仅供记录,比较:

    spam == eggs
如果它们中的任何一个可能是由Model.objects.raw()查询创建的延迟模型实例或者应用于“普通”QuerySet的.defer(),则

是危险的。

我在此处提供了更多详细信息:Django QuerySet .defer() problem - bug or feature?

答案 5 :(得分:1)

正如orokusaki评论,“如果两个实例都没有主键,它将始终返回true”。如果您希望这样做,您可以扩展您的模型:

def __eq__(self, other):
    eq = isinstance(other, self.__class__) and self._get_pk_val() == other._get_pk_val()

    if eq and self._get_pk_val() is None:
        return id(self) == id(other)
    return eq

答案 6 :(得分:0)

如果两个模型实例具有不同的属性,那么将它们视为相等将会很奇怪。大部分时间都是不可取的。

你想要的是一个特例。比较spam.pk == eggs.pk是一个好主意。如果还没有pk,因为它们尚未保存,那么如果某些属性不同,则更难定义哪些实例“真的”相同。

如何在创建实例时为您的实例添加自定义属性,例如: spam.myid=1eggs.myid=2

spamcopy1.seasoning=ketchupspamcopy2.seasoning=blackpepper时,您可以在代码的某个时刻比较他们的myid属性,看看他们是否真的是“相同的”垃圾邮件。

答案 7 :(得分:0)

来自https://djangosnippets.org/snippets/2281/

我更改为比较两个实例并返回布尔值

obj.a().b