首页 文章

Django比较模型实例的相等性

提问于
浏览
30

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

spam == eggs

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

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

spam.pk == eggs.pk

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

更新(02-27-2015)

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

7 回答

  • 5

    正如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
    
  • 17

    仅供记录,比较:

    spam == eggs
    

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

    我在这里提供了更多细节:Django QuerySet .defer() problem - bug or feature?

  • 4

    来自django documentation

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

  • 60

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

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

    spam.pk == eggs.pk
    

    编辑:btw在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 不起作用?

  • 0

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

    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
    

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

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

  • 6

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

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

  • 1

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

    你想要的是一个特例 . 比较 spam.pk == eggs.pk 是个好主意 . 如果还没有 pk ,因为如果某些属性不同,它们很难定义哪些实例是"really"相同 .

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

    这种方式在代码中的某些时候 spamcopy1.seasoning=ketchupspamcopy2.seasoning=blackpepper 可以比较它们的 myid 属性,看它们是否真的是"same"垃圾邮件 .

相关问题