Opened 5 years ago

Closed 5 years ago

#20105 closed Uncategorized (invalid)

dictsort by obj and by obj_id gives varying results

Reported by: apollovy@… Owned by: nobody
Component: Template system Version: 1.5
Severity: Normal Keywords: dictsort, sorting, grouping, regroup, templatetag
Cc: bmispelon@… Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


Hello there.


I've got a model:

class MyModel(Model):
 obj = ForeignKey(SomeOtherModel)

I've got a view:

class MyView(ListView):
 def get_context_data(self):
  return {'objects': MyModel.objects.all()}

Then I've got a template:

{% regroup objects|dictsort:'obj_id' by obj %}
{% regroup objects|dictsort:'obj' by obj %}

And I've got data:

MyModel: [{id: 1, obj: 1},{id: 2, obj: 1},{id: 3, obj: 2},{id: 4, obj: 2},{id: 5, obj: 1}]
SomeOtherModel: [{id: 1},{id: 2}]

Dictsort in first case works well and predictable.
Second case - no way to figure out. One time objects got grouped in 2 groups, as expected. The other time - in 3 groups. The other time - in 4(!) groups.

Guess this behaviour is not meant.

Change History (2)

comment:1 Changed 5 years ago by Baptiste Mispelon

Cc: bmispelon@… added


MyModel.obj_id will give you back an integer so sorting a list according to this attribute is straightforward and does what you expect.

However, MyModel.obj will give you back an instance of SomeOtherModel, which causes the behaviour you're describing, because comparing two model instances is somehow undefined (technically, it's very well defined but it most likely never does what you want).

The technical reason behind that is that django's models don't implement a __cmp__ method so when comparing them, python falls back to comparing their id (id being the python builtin function, not the primary key of the model) which is not consistent.

See for more details.

Note that this is not applicable to python3 where comparing two model instances together will fail with a TypeError.

comment:2 Changed 5 years ago by Baptiste Mispelon

Resolution: invalid
Status: newclosed

I'm going to mark this as invalid, since this is not a bug but only a python2 "quirk".

Note: See TracTickets for help on using tickets.
Back to Top