views:

169

answers:

4

I understand that, with a singleton situation, you can perform such an operation as:

spam == eggs

and if spam and eggs are instances of the same class with all the same attribute values, it will return True. In a Django model, this is natural because two separate instances of a model won't ever be the same unless they have the same .pk value.

The problem with this is that if a reference to an instance has attributes that have been updated by middleware somewhere along the way and it hasn't been saved, and you're trying to it to another variable holding a reference to an instance of the same model, it will return False of course because they have different values for some of the attributes. Obviously I don't need something like a singleton , but I'm wondering if there some official Djangonic (ha, a new word) method for checking this, or if I should simply check that the .pk value is the same with:

spam.pk == eggs.pk

I'm sorry if this was a huge waste of time, but it just seems like there might be a method for doing this, and something I'm missing that I'll regret down the road if I don't find it.

+2  A: 

You can define the Class' __eq__ method to chage that behaviour:

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

piotr
I would do that, but I don't want o have to do it over and over again.
orokusaki
+3  A: 

spam.pk == eggs.pk is a good way to do that.

You may add __eq__ etc to your model but I will avoid that , because it is confusing and == can mean different things in different contexts, e.g. i may want == to mean that content is same , id may differ, so again best way is

spam.pk == eggs.pk

Edit: btw in django 1.0.2 Model class has defined eq as

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

which seems to be same as spam.pk == eggs.pk as pk is property which uses _get_pk_val so I don't see why spam == eggs not working ?

Anurag Uniyal
It seems like that functionality should safely be built-in to the already overloaded `__eq__` method on `Model`, but currently if you use `a == b` and both objects don't have a `pk`, it returns `True` which is odd. Thanks, I'll stick to that method.
orokusaki
@orokusaki, see the edit.
Anurag Uniyal
@Anurag Interesting. The problem is that if neither instance has a primary key, it will return true always. So if you have 5 model instances that you want to test against each other and none have been saved, they could all be different, but they will test `__eq__` as `True`.
orokusaki
A: 

It would be strange if two model instances compared as equal if they had different attributes. Most of the time that would be undesirable.

What you want is a special case. Comparing spam.pk == eggs.pk is a good idea. If there's no pk yet as they haven't been saved then it's harder to know which instances are 'really' the same if some attributes are different.

How about adding a custom attribute to your instances when creating them, eg: spam.myid=1, eggs.myid=2

That way at some point in your code when spamcopy1.seasoning=ketchup and spamcopy2.seasoning=blackpepper you can compare their myid attribute to see if they're really the 'same' spam.

Anentropic
+1  A: 

Just for the record, comparing:

    spam == eggs

is dangerous if there is any chance that either of them could be a deferred model instance created by Model.objects.raw() query or by .defer() applied to a 'normal' QuerySet.

I put more details here: http://stackoverflow.com/questions/3617886/django-queryset-defer-problem-bug-or-feature

Tomasz Zielinski