Skip to content

Commit

Permalink
Support ordering tags by specified field
Browse files Browse the repository at this point in the history
  • Loading branch information
kavdev authored and Asif Saif Uddin committed Jul 14, 2021
1 parent 3847b3c commit 4e75afe
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 2 deletions.
13 changes: 11 additions & 2 deletions taggit/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,16 @@ def clone(self):
class _TaggableManager(models.Manager):
# TODO investigate whether we can use a RelatedManager instead of all this stuff
# to take advantage of all the Django goodness
def __init__(self, through, model, instance, prefetch_cache_name):
def __init__(self, through, model, instance, prefetch_cache_name, ordering=None):
super().__init__()
self.through = through
self.model = model
self.instance = instance
self.prefetch_cache_name = prefetch_cache_name
if ordering:
self.ordering = ordering
else:
self.ordering = []

def is_cached(self, instance):
return self.prefetch_cache_name in instance._prefetched_objects_cache
Expand All @@ -73,7 +77,9 @@ def get_queryset(self, extra_filters=None):
return self.instance._prefetched_objects_cache[self.prefetch_cache_name]
except (AttributeError, KeyError):
kwargs = extra_filters if extra_filters else {}
return self.through.tags_for(self.model, self.instance, **kwargs)
return self.through.tags_for(self.model, self.instance, **kwargs).order_by(
*self.ordering
)

def get_prefetch_queryset(self, instances, queryset=None):
if queryset is not None:
Expand Down Expand Up @@ -429,6 +435,7 @@ def __init__(
blank=False,
related_name=None,
to=None,
ordering=None,
manager=_TaggableManager,
):
self.through = through or TaggedItem
Expand All @@ -444,6 +451,7 @@ def __init__(
rel=rel,
)

self.ordering = ordering
self.swappable = False
self.manager = manager

Expand All @@ -458,6 +466,7 @@ def __get__(self, instance, model):
model=model,
instance=instance,
prefetch_cache_name=self.name,
ordering=self.ordering,
)

def deconstruct(self):
Expand Down
38 changes: 38 additions & 0 deletions tests/migrations/0005_auto_20210713_2301.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Generated by Django 3.2.4 on 2021-06-19 08:26

from django.db import migrations, models

import taggit.managers


class Migration(migrations.Migration):

dependencies = [
("tests", "0004_auto_20210619_0826"),
]

operations = [
migrations.CreateModel(
name="OrderedModel",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"tags",
taggit.managers.TaggableManager(
help_text="A comma-separated list of tags.",
through="taggit.TaggedItem",
to="taggit.Tag",
verbose_name="Tags",
),
),
],
),
]
4 changes: 4 additions & 0 deletions tests/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,3 +408,7 @@ class Meta:
# HINT: Rename field 'Tag.name', or add/change a related_name argument to the definition for field 'Name.tags'.
class Name(models.Model):
tags = TaggableManager(related_name="a_unique_related_name")


class OrderedModel(models.Model):
tags = TaggableManager(ordering=["name"])
12 changes: 12 additions & 0 deletions tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
OfficialPet,
OfficialTag,
OfficialThroughModel,
OrderedModel,
Pet,
Photo,
ProxyPhoto,
Expand Down Expand Up @@ -1262,3 +1263,14 @@ def test_custom_related_name(self):
name.tags.add("foo")
tag = Tag.objects.get(a_unique_related_name=name.pk)
self.assertEqual(tag.name, "foo")


class OrderedTagsTest(TestCase):
def test_added_tags_are_returned_ordered(self):
obj = OrderedModel.objects.create()
obj.tags.add("green", "red", "orange", "yellow", "blue")

self.assertListEqual(
["blue", "green", "orange", "red", "yellow"],
list(obj.tags.values_list("name", flat=True)),
)

0 comments on commit 4e75afe

Please sign in to comment.