查找相关对象并显示关系

时间:2013-05-22 14:42:39

标签: python django django-models django-orm

我正在使用django-follow来允许用户“关注”对象 - 在本例中,是电影中的演员。

我正在使用

撤回电影演员名单
 actors_user_is_following = Follow.objects.get_follows(Actor).filter(user=request.user.id)

但我还想做的是根据他们所关注的演员向用户推荐电影。这不需要是他们已经喜欢的复杂算法,并建议相关电影,只是一个简单的“因为你跟随这个演员和这个演员是在这部电影,建议用户”

我现在有这种相当笨重的方式来做这件事......

    context['follows'] = {
        'actors': Follow.objects.get_follows(Actor).filter(user=request.user.id),
        'genres': Follow.objects.get_follows(Genre).filter(user=request.user.id),
    }

    actor_ids = []
    for actor in context['follows']['actors']:
        actor_ids.append(actor.target_artist_id)

    genre_ids = []
    for artist in context['follows']['genres']:
        genre_ids.append(artist.genre_ids)

    context['suggested'] = {
        'films': Listing.objects.filter(Q(actors__in=actor_ids) | Q(genres__in=genre_ids))
    }

哪个有效,但我确定有更好的方法吗?

最重要的是我还想向用户展示为什么通过显示用户所关注的演员或类型来推荐该电影,所以最终结果可能是......

film = {
 title: 'Dodgeball'
 image: '/images/films/dodgeball.jpg'
 followed_actors: ['Ben Stiller', 'Vince Vaughn'] #could be multiple
 followed_genres: ['Comedy'] #could be multiple
}

注意我想要回复多部电影。

以下是我的模型的编码方式:

电影模型定义如下:

from django.db import models
from app.actors.models import Actor
from app.genres.models import Genre


class Film(models.Model):
    title = models.CharField(max_length=255)
    strapline = models.CharField(max_length=255)
    slug = models.SlugField(max_length=100)
    image_url = models.CharField(max_length=255)
    pub_date = models.DateTimeField('date published')
    actors = models.ManyToManyField(Actor)
    genres = models.ManyToManyField(Genre)

    def __unicode__(self):
        return self.title

和演员模特:

from django.db import models

from follow import utils


class Actor(models.Model):
    title = models.CharField(max_length=255)
    strapline = models.CharField(max_length=255)
    image = models.CharField(max_length=255)
    image_hero = models.CharField(max_length=255)
    bio = models.TextField()

    def __unicode__(self):
        return self.title


#followable
utils.register(Actor)

1 个答案:

答案 0 :(得分:2)

在幕后,Follow对象本质上是一个多对多关系,每次注册模型时都会添加字段。

你的问题只是谈论演员,但你的代码也包括类型。它并不是特别难以涵盖两者,我只是不确定你想要它的方式。

我认为你可以在一个查询集中获取你的电影对象:

films = Film.objects.filter(Q(actors__in=Actor.objects.filter(follow_set__user=request.user)) |
                Q(genres__in=Genre.objects.filter(follow_set__user=request.user))).distinct()

正如__in lookups的文档中所述,如果在使用子查询之前评估子查询,某些数据库后端将为您提供更好的性能:

actor_ids = list(Actor.objects.filter(follow_set__user=request.user).values_list('id', flat=True))
genre_ids = list(Genre.objects.filter(follow_set__user=request.user).values_list('id', flat=True))
films = Film.objects.filter(Q(actors__in=actor_ids) | Q(genres__in=genre_ids)).distinct()

如果您只是想要回复相应的影片,我认为这些是最简洁的表达方式。

对于您在电影中添加原因的部分 - 我没有看到更优雅的方式来处理这些,而不是迭代电影查询集并手动添加信息。在这样做之前,我肯定会定义actor_ids和genre_ids的查询集,不管我是否提前评估它们仍然依赖于db后端。

annotated_films = []
for film in films:
    film.followed_actors = film.actors.filter(id__in=actor_ids)
    film.followed_genres = film.genres.filter(id__in=genre_ids)
    annotated_films.append(film)