#django-taggit, how to get all tags of a specific model only?

60 messages · Page 1 of 1 (latest)

ionic bay
#

If I have tags field on several models, then Tag.objects.all() will get me all tags across all models.
Not having found a shortcut, by the docs, is this setup correct?:
-remove taggit from installed_apps
-in models.py:

class TaggedFood(TaggedItemBase):
    content_object = models.ForeignKey('Food', on_delete=models.CASCADE)

class Food(models.Model):
    tags = TaggableManager(through=TaggedFood)

Then will I be able to access tags only on Food model with TaggedFood.objects.all()?

When making migrations for this setup I get: "my_app.Food.tags: (fields.E300) Field defines a relation with model 'Tag', which is either not installed, or is abstract."

The setup is from here https://django-taggit.readthedocs.io/en/latest/custom_tagging.html

wise lichen
#

You can not remove taggit from installed apps, no

#

Or, hang on ....

#

I used to have a custom through model, but i am 75% sure i did not remove taggit from installed apps ... And it sounds weird 🤔

#

Also, neither of the examples of what this will help with matches your problem.

#

Food.objects.filter(tags__name__in=["delicious", "red"]).distinct()

#

Or are you looking for all food that is tagged or not? If so, a null check on Food.tags should do the trick.

ionic bay
wise lichen
#

Yeah. But to do what you want what they write there is not required.

#

See the last message i wrote with example.

ionic bay
#

So again, what I want. I do not want to query the Model. I would like to display All tags on that model only. If I have 2 models; Foods and Drinks. Both have tag 'sweet'. Then I have 2 separate list pages for Food and Drinks. Both can query on 'sweet' tag.

#

But I do not want the sweet drinks to appear on Food page and vice versa.

ionic bay
wise lichen
#

Something like Food.objects.all().values("tags").distinct() would display all possible tags on foods methinks?

#

After that, what they "display" when you click on the different tags on a page is all up to your template/view code 🤔

wise lichen
#
>>> Food.objects.all()
<QuerySet [<Food: Food: Red berries (red,berry,sweet)>, <Food: Food: Pancakes (baked goods,sweet)>]>
>>> Drink.objects.all()
<QuerySet [<Drink: Food: Water (sugarfree,bland)>, <Drink: Food: Coke (sugar,sweet,coffeine,black)>, <Drink: Food: Fanta (sugar,sweet,yellow)>]>
#
Food.objects.values_list("tags__name",flat=True).distinct()
<QuerySet ['red', 'berry', 'sweet', 'baked goods']>
#
>>> Food.objects.filter(tags__name__in=["sweet", "red"])
<QuerySet [<Food: Food: Red berries (red,berry,sweet)>, <Food: Food: Red berries (red,berry,sweet)>, <Food: Food: Pancakes (baked goods,sweet)>]>                 >>> Food.objects.filter(tags__name__in=["sweet"]).filter(tags__name__in=["red"])
<QuerySet [<Food: Food: Red berries (red,berry,sweet)>]>
#
>>> Drink.objects.filter(tags__name__in=["sweet"])
<QuerySet [<Drink: Food: Coke (sugar,sweet,coffeine,black)>, <Drink: Food: Fanta (sugar,sweet,yellow)>]>
ionic bay
#

Yes! That is much closer: tags = Food.objects.all().values("tags").distinct()
It gets not an ideal list of tags ids
<QuerySet [{'tags': 1}, {'tags': 3}, {'tags': 5}, {'tags': 1}, {'tags': 2}, {'tags': 3}, {'tags': 4}, {'tags': 5}]>
Objects with name, slug attributes like from Tag.objects.all() would have been ideal.

And distinct() does not work on it.
So I do some manual python:

>>> L = set()
>>> for tag in tags:
...     L.add(tag['tags'])
... 
>>> L
{1, 2, 3, 4, 5, 6, 7}
>>> tags_objects = []

>>> for id in L:
...     tags_objects.append(Tag.objects.get(id=id))
... 
>>> tags_objects
[<Tag: brown>, <Tag: tasty>, <Tag: ...>]

So I could do in template

>>> tags_objects[0].slug
'brown'
#

Thank you!

wise lichen
#

Do you not want want values_list("tags__name", flat=True), not values("tags")?

#

Or tags__slug ?

#

You do not need to go via the IDs and loop.

#
>>> Food.objects.values_list("tags__slug",flat=True)
<QuerySet ['red', 'berry', 'sweet', 'sweet', 'baked-goods']>                                                >>> Food.objects.values_list("tags__slug",flat=True).distinct()
<QuerySet ['red', 'berry', 'sweet', 'baked-goods']>
#

The last one gives you what you want no, a simple list of tags slugs?

ionic bay
#

I was just thinking of the simplest way to display tags in template.

{% for tag in tags %}
    <button hx-get="{% url 'app:list_by_tag' tag.slug %}" >{{ tag.name }}</button>

That is why was thinking of making a list of tags objects.

Otherwise I would have to traverse 2 lists (names and slugs) in parallel. Could, if the order of 2 lists is guaranteed to be the same and with no dups.
But for some reason on my end, there are still duplicates after applying .distinct().

>>> tags = Model.objects.values_list("tags__name", flat=True)
>>> tags
<QuerySet ['brown', 'white', 'brown', 'white', ..]>
>>> tags.distinct()
<QuerySet ['brown', 'white', 'brown', 'white', ..]>

>>> tags_slugs_dist = Model.objects.values_list("tags__slug", flat=True).distinct()
>>> tags_slugs_dist
<QuerySet ['brown', 'white', 'brown', 'white', ..]>
wise lichen
#

Just do

<QuerySet [('red', 'red'), ('berry', 'berry'), ('sweet', 'sweet'), ('baked-goods', 'baked goods')]>

Then you have a list of (slug, name)?

ionic bay
#

Yes, nice! In general this way would work. But for me it stubbornly leaves duplicates.

> Food.objects.values_list("tags__slug", "tags__name").distinct()
> <QuerySet [('brown', 'brown'), ('white', 'white'), ('brown', 'brown'), ('white', 'white'), ...]>
wise lichen
#

🤔

#

Weeeeird

ionic bay
#

OK, I think just using set() on it worked!

wise lichen
#

It should not be required 🤔

ionic bay
#

Then all set to use your way.

ionic bay
wise lichen
#
>>> qs = Food.objects.values_list("tags__slug", "tags__name").distinct()

>>> print(qs.query)
SELECT DISTINCT 
    "taggit_tag"."slug",
    "taggit_tag"."name"
FROM
    "mysite_food"
LEFT OUTER JOIN
  "taggit_taggeditem"
    ON
    ("mysite_food"."id" 
      = "taggit_taggeditem"."object_id" 
      AND ("taggit_taggeditem"."content_type_id" = 11)) 
LEFT OUTER JOIN
    "taggit_tag"
    ON
    ("taggit_taggeditem"."tag_id"
      =
      "taggit_tag"."id")
#

What is your sql query?

ionic bay
#
SELECT DISTINCT "taggit_tag"."slug", "taggit_tag"."name", "gallery_printing_printphoto"."added" FROM "gallery_printing_printphoto" LEFT OUTER JOIN "taggit_taggeditem" ON ("gallery_printing_printphoto"."id" = "taggit_taggeditem"."object_id" AND ("taggit_taggeditem"."content_type_id" = 13)) LEFT OUTER JOIN "taggit_tag" ON ("taggit_taggeditem"."tag_id" = "taggit_tag"."id") ORDER BY "gallery_printing_printphoto"."added" DESC
#

Maybe I should mention, my tag names are not in English. Maybe django-taggit has a problem with that.

wise lichen
#

So the different tags will have different .added, and thus not be distinct ?

#

Are they all written using the same, normalized unicode way?

#

If you try to do just slugs (they should be unique and ascii), are the results distinct?

ionic bay
#

different added

#

I am indexing on that, on added

wise lichen
#

But it is required in this list generation?

ionic bay
#

Slugs are unicode and they also still have dups after using .distinct().

wise lichen
#

Yeah, but why is this added field even in the query?

#

What is you actual ORM calls to get that SQL query?

ionic bay
#

My model has

class PrintPhoto(models.Model):
    title = models.CharField(max_length=200)
    slug = models.SlugField(max_length=200, blank=True)
    photo = models.ImageField(upload_to="gallery_printing/%Y/")
    description = models.TextField(blank=True)
    added = models.DateField(auto_now_add=True)
    tags = TaggableManager()
    class Meta:
        indexes = [
            models.Index(fields=["-added"]),
        ]
        ordering = ["-added"]

ORM is just

>>> tags4 = PrintPhoto.objects.values_list("tags__slug", "tags__name").distinct()
>>> tags4
<QuerySet [('brown', 'mybrownnotEng'), ('white', 'mywhite'), ('brown', 'mybrownnotEng'), ..]>
>>> print(tags4.query)
SELECT DISTINCT "taggit_tag"."slug", "taggit_tag"."name", "gallery_printing_printphoto"."added" FROM "gallery_printing_printphoto" LEFT OUTER JOIN "taggit_taggeditem" ON ("gallery_printing_printphoto"."id" = "taggit_taggeditem"."object_id" AND ("taggit_taggeditem"."content_type_id" = 13)) LEFT OUTER JOIN "taggit_tag" ON ("taggit_taggeditem"."tag_id" = "taggit_tag"."id") ORDER BY "gallery_printing_printphoto"."added" DESC
wise lichen
#

If you remove the default ordering from the Model.Meta, the distinct tags query will probably work 🤔

#

Try this to clear the ordering?

#

Just .order_by() should clear the default ordering according to docs.

ionic bay
#

And yes it does

#

🙃

#

That was some mystery search 🙂

#

Thank you!!

wise lichen
#

@brave cypress ^ ref

#

Glad to be helpful. Have you solved all your taggit-related quandries now?