Chozabu
Chozabu

Reputation: 1023

Sort by a value in a many to one field with a django queryset?

I have a data model like this:

class Post(models.Model)
    name = models.CharField(max_length=255)

class Tag(models.Model)
    name = models.CharField(max_length=255)
    rating = models.FloatField(max_length=255)
    parent = models.ForeignKey(Post, related_name="tags")

I want to get Posts that have a tag, and order them by the tags rating.

something like: Posts.objects.filter(tags__name="exampletag").order_by("tags(name=exampletag)__rating")

Currently, I am thinking it makes sense to do something like

tags = Tags.objects.filter(name="sometagname").order_by("rating")[0:10]
posts = [t.parent for t in tags]

But I like to know if there is a better way, preferably querying Post, and getting me back a queryset.


Edit:

I don't think this: (Edit 2 - this does give the correct sorting!)

Posts.objects.filter(tags__name="exampletag").order_by("tags__rating")

will give the correct sorting, as it does not sort only by the related item with name "exampletag"
Something like the following would be needed

Posts.objects.filter(tags__name="exampletag").order_by("tags(name=exampletag)__rating")

I've been looking over the django docs, and it seem "annotate" nearly works - but I don't see a way to use it to select a tag by name.


Edit 2

Both the Answers are correct! See my comments to observe some epic brain-farts (one test, the results WERE in order, the other i filter and sort by different tags!)

how it works

the query

Posts.objects.filter(tags__name="exampletag").order_by("tags__rating")

and

Posts.objects.filter(tags__name="exampletag").filter(tags__name="someothertag").order_by("tags__rating")

will work correctly and by sorted by the rating of "exampletag"

it seems the tag(From a ForeignKey BackReference Set) used for sorting when calling order_by is the one in the first filter.

Upvotes: 0

Views: 1862

Answers (2)

Anush Devendra
Anush Devendra

Reputation: 5475

You can do like:

tags = Tags.objects.filter(name="sometagname")
posts =  Post.objects.filter(tags__in=tags).order_by('tags__rating')

Upvotes: 2

Daniel Roseman
Daniel Roseman

Reputation: 599490

Even shorter than Anush's, with a JOIN rather than a subquery:

Post.objects.filter(tags__name='exampletag').order_by('tags__rating')

Upvotes: 1

Related Questions