0

Hello,

Can some good person give me advice on how to get a queryset of ordered objects by intersecting a many-to-many field with a given one object's many-to-many field?

For example I have:

class Video(models.Model):
tags = models.ManyToManyField(Tag, blank=True)

...

class Tag(models.Model):
name = models.CharField(max_length=64)

...

I select one Video object and would like to have first ten objects that have most similar tags set to show like related videos.

Thanks in advance!

Vevs
  • 27
  • 5

1 Answers1

1

I made a simple example, this should work

tag1 = Tag.objects.create(name="test video") #create a tag
video1 = Video.objects.create() #create a video
video1.tags.add(tag1) #add tag to video

video_query = Video.objects.filter(tags__name="test video")
print("query",video_query)

Now in this example its only 1 tag but if you have 100 tags put [:11] after video_query = Video.objects.filter(tags__name="test video")[:11]

This will give you the exact match.

If you use:

 video_query = Video.objects.filter(tags__in=example_video.tags.all())

You will get a query with all the videos with at least 1 matching tag, if a video has 2 matching tags it will be present 2 times in the query. You can fetch the videos which are present multiple times in the query. You need to exclude example_video from the query

saro
  • 705
  • 3
  • 13
  • This approach does not work because each video has several tags. So we need to find the 10 videos that have the most similar set of tags. It should be some ordering by amount of intersections two tags sets. Btw if you write `related_videos = Video.objects.filter(tags=video.tags)[:11]` you got the next error: `Field 'id' expected a number but got .ManyRelatedManager object at 0x000002A5CE6DA7D0>` – Vevs Apr 21 '22 at 08:37
  • what you are doing is not right. You have to type a name in the filter not video.tags. You have to type the name of the tag – saro Apr 21 '22 at 10:25
  • i updated the answer with an example – saro Apr 21 '22 at 11:31
  • May be I didn't explain enough the issue: the problem is not to find all videos with some tag (that you did in your example) the aim is to find most relevant videos to particular video by comparing their tags set. For example we have three videos: video1(tag1, tag2), video2(tag2, tag3), video3(tag1, tag2, tag3). So when we try to found the relevant video to video1 we see that video3 has more similar tags to video1 tags than video2. Therefor video3 is relevant to video1. – Vevs Apr 21 '22 at 15:20
  • I just made it by the python script, but I belive there is some way to make the same on the ORM side: `video = Video.objects.prefetch_related('actors', 'tags').get(static_url=url) video_tags = scene.tags.all() all_videos = Video.objects.prefetch_related('actors', 'tags').exclude(id=video.id).all() related_videos = sorted(all_videos, key=lambda x: len(video_tags.intersection(x.tags.all())), reverse=True)[:11]` – Vevs Apr 21 '22 at 15:44
  • see my updatet answer. – saro Apr 21 '22 at 16:01
  • Thanks for advice. Could you also tell me how to get a query set order by quantity of present the objects and it should be distinct? I know to do that by python but I hope there is better solution to do this on the ORM side. I found similar question and solution looks little bit complicated )) : [link](https://stackoverflow.com/questions/51507828/django-annotate-the-count-of-the-number-of-duplicate-values-for-each-object) – Vevs Apr 21 '22 at 22:10