Home > Software engineering >  Order django queryset by rank of related tags
Order django queryset by rank of related tags

Time:01-02

I'm a little stuck on something. I'm trying to create a cheatsheets app where the user can upvote other users posts.

I'm using django-taggit to manage tags and django-vote for voting functionality. This is my model:

class Cheatsheet(VoteModel, models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
    title = models.CharField(max_length=500, null=True, blank=True, default="")
    description = models.CharField(
        max_length=500, null=True, blank=True, default="")
    tags = TaggableManager(blank=True)

    def __str__(self):
        return self.title

and this is the view:

class CheatsheetViewSet(viewsets.ModelViewSet, VoteMixin):
    queryset = Cheatsheet.objects.all()
    serializer_class = CheatsheetSerializer
    http_method_names = ['get', 'post', 'retrieve', 'put', 'patch', 'delete']

I'm trying to sort cheatsheets based on the tags related to previously upvoted posts. I have managed to obtain a "tag rank" based on the posts that the user has upvoted. For example if the user upvoted a post with the tags "css" and "js" and another post with only the tag "css" user_tag_rank would result in something like this:

{"css": 2, "js": 1}

I would like to order the posts based on this rank, with tags with the most upvotes first. In this case all posts with the tag "css" would come first, then posts with the tag "js" and then any other posts. The question is how do I go about sorting the posts based on this user tag rank? Is this even possible?

CodePudding user response:

The difficulty is because of the data structures we're working with. The Cheatsheets are separate from their tags, and the tags are separate from their ranks (which makes sense because ranks are personalized to each user).

To make the sorting algorithm simpler, we can first transform the data structure to help us:

tag_ranks = [
    {id: 'css', rank: 1},
    {id: 'js', rank: 2}
]

def get_rank_of_cheatsheet_tag(cheatsheet_tag, tag_ranks):
    """ Returns the rank of a tag """
    return next((t for t in tag_ranks if t.id == cheatsheet_tag.id), None)

def highest_tag_of_cheatsheet(cheatsheet_tags, tag_ranks):
    """ Returns the rank of the highest-ranking tag """

    # First let's enrich the cheatsheet tags with the ranks that we have
    enriched_cheatsheet_tags = []
    for cheatsheet_tag in cheatsheet_tags:
        enriched_cheatsheet_tags.append(
        {
            id = cheatsheet_tag.id,
            rank = cheatsheet_tag.rank
            weight = get_rank_of_cheatsheet_tag(cheatsheet_tags, tag_ranks)
        }
    )

    # now that each tag has a rank, it's easy to sort them
    highest_ranking_tag = max(enriched_cheatsheet_tags, key=lambda tag: tag.rank)

    return highest_ranking_tag.rank

cheatsheets = Cheatsheet.objects.all() # or whatever your queryset is
cheatsheets.sort(key=highest_tag_of_cheatsheet)

I didn't actually run this code, so I don't know if I have syntax errors anywhere, but you can stfollow the same logic pretty much.

  • Related