diff --git a/modelcluster/queryset.py b/modelcluster/queryset.py index bd021ac..00ffade 100644 --- a/modelcluster/queryset.py +++ b/modelcluster/queryset.py @@ -516,6 +516,18 @@ def order_by(self, *fields): clone = self.get_clone(results=self.results[:]) sort_by_fields(clone.results, fields) return clone + + def distinct(self, *fields): + unique_results = [] + if not fields: + fields = [field.name for field in self.model._meta.fields if not field.primary_key] + seen_keys = set() + for result in self.results: + key = tuple(str(extract_field_value(result, field)) for field in fields) + if key not in seen_keys: + seen_keys.add(key) + unique_results.append(result) + return self.get_clone(results=unique_results) # a standard QuerySet will store the results in _result_cache on running the query; # this is effectively the same as self.results on a FakeQuerySet, and so we'll make diff --git a/tests/tests/test_cluster.py b/tests/tests/test_cluster.py index 7abd3ad..be55a25 100644 --- a/tests/tests/test_cluster.py +++ b/tests/tests/test_cluster.py @@ -796,6 +796,28 @@ def test_meta_ordering(self): albums = [album.name for album in beatles.albums.all()] self.assertEqual(['With The Beatles', 'Please Please Me', 'Abbey Road'], albums) + def test_distinct_with_no_fields(self): + beatles = Band(name='The Beatles', albums=[ + Album(name='Please Please Me', sort_order=1), + Album(name='With The Beatles', sort_order=2), + Album(name='Abbey Road', sort_order=2), + ]) + + albums = [album.name for album in beatles.albums.order_by('sort_order').distinct()] + self.assertEqual(['Please Please Me', 'With The Beatles', 'Abbey Road'], albums) + + def test_distinct_with_fields(self): + beatles = Band(name='The Beatles', albums=[ + Album(name='Please Please Me', sort_order=1), + Album(name='With The Beatles', sort_order=2), + Album(name='Abbey Road', sort_order=2), + ]) + albums = [album.name for album in beatles.albums.order_by('sort_order').distinct('sort_order')] + self.assertEqual(['Please Please Me', 'With The Beatles'], albums) + + albums = [album.name for album in beatles.albums.order_by('sort_order').distinct('name')] + self.assertEqual(['Please Please Me', 'With The Beatles', 'Abbey Road'], albums) + def test_parental_key_checks_clusterable_model(self): from django.core import checks from django.db import models