Question: I'm testing the update of an application from Django 2.1.7 to 2.2.12. I got an error when running my unit tests, which boils down to a model object not being hashable :  Station.objects.all().delete() py37\lib\site-packages\django\db\models\query.py:710: in delete collector.collect(del_query) py37\lib\site-packages\django\db\models\deletion.py:192: in collect reverse_dependency=reverse_dependency) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <django.db.models.deletion.Collector object at 0x000001EC78243E80> objs = <QuerySet [<Station(nom='DUNKERQUE')>, <Station(nom='STATION1')>, <Station(nom='STATION2')>]>, source = None, nullable = False reverse_dependency = False def add(self, objs, source=None, nullable=False, reverse_dependency=False): """ Add 'objs' to the collection of objects to be deleted. If the call is the result of a cascade, 'source' should be the model that caused it, and 'nullable' should be set to True if the relation can be null. Return a list of all objects that were not already collected. """ if not objs: return [] new_objs = [] model = objs[0].__class__ instances = self.data.setdefault(model, set()) for obj in objs: > if obj not in instances: E TypeError: unhashable type: 'Station'  Instances of model objects are hashable in Django, once they are saved to database and get a primary key. I don't understand where the error comes from and why I get this when running this basic code: In [7]: s = Station.objects.create(nom='SOME PLACE') In [8]: hash(s) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-8-9333020f3184> in <module> ----> 1 hash(s) TypeError: unhashable type: 'Station' In [9]: s.pk Out[9]: 2035  All this code works fine when I switch back to Django 2.1.7. The same happens with other model objects in the app. I'm using python version 3.7.2 on Windows, with a SQlite backend (on the development workstation). Edit: Here's the definition of the model referred to above: class Station(models.Model): nom = models.CharField(max_length=200, unique=True) def __str__(self): return self.nom def __repr__(self): return "<Station(nom='{}')>".format(self.nom) def __eq__(self, other): return isinstance(other, Station) and self.nom == other.nom 

Answer: As pointed out by @Alasdair, the issue was a change of behaviour brought in Django 2.2 to comply with how a model class should behave when __eq__() is overriden but not __hash__(). As per the python docs for __hash__():  A class that overrides __eq__() and does not define __hash__() will have its __hash__() implicitly set to None.  More information about the implementation of this behaviour in Django can be found in this ticket. The fix can be either the one suggested in the ticket, i.e. re-assigning the __hash__() method of the model to the one of the super class: __hash__ = models.Model.__hash__ Or a more object-oriented way could be:  def __hash__(self): return super().__hash__()  This seems a bit weird because this should be unnecessary: by default, a call to __hash__() should use the method from the super class where it's implemented. This suggests Django breaks encapsulation somehow. But maybe I don't understand everything. Anyway that's a sidenote. In my case, I still wanted to be able to compare model instances not yet saved to the database for testing purposes and ended up with this implementation :  def __hash__(self): if self.pk is None: return hash(self.nom) return super().__hash__()