You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中匹配用户收藏多对多流派字段并展示对应内容

问题描述

我正在开发一个包含三类帖子的项目:

  • 电影(模型名List)
  • 音乐(模型名MusicList)
  • 书籍(模型名BookList)

每类对应独立模型,且各自拥有专属流派模型:Genre(电影)、MusicGenre(音乐)、BookGenre(书籍)。

系统中有Profile模型,包含fav_music_genre、fav_movie_genre、fav_Book_genre三个多对多字段,用于存储用户收藏的流派。

需要在视图的all(首页)函数中编写代码,对比当前登录用户的上述收藏流派字段,仅展示流派匹配的List、MusicList和BookList内容。例如:若用户收藏了Action与Comedy流派,则只显示包含这两个流派的列表内容。

我是Python/Django新手,为此困惑了4-6天,找不到解决思路。以下是我的models.py代码:

class MusicList(models.Model):
    title = models.CharField(max_length=120)
    genre = models.ManyToManyField('MusicGenre')
    creator = models.ForeignKey(User,on_delete=models.SET_NULL,blank=True, null=True)
    posted = models.DateTimeField(auto_now_add=True)
    content = RichTextField(null=True,default=' ')
    type = models.CharField(max_length=10,default="Music")
    slug = models.SlugField(max_length= 300,null=True, blank = True, unique=True)


    def __str__(self):
        return f'{self.title}|{self.creator}'
    def save(self, *args, **kwargs):
        self.slug = slugify(self.title + str(self.posted))
        super(MusicList,self).save(*args, **kwargs)



class MusicGenre(models.Model):
    name = models.CharField(max_length=150)

    def __str__(self):
        return self.name



class BookList(models.Model):
    title = models.CharField(max_length=120)
    creator = models.ForeignKey(User,on_delete=models.SET_NULL,blank=True, null=True)
    genre = models.ManyToManyField('BookGenre')
    posted = models.DateTimeField(auto_now_add=True)
    spoiler_choices = [(False, 'No'),(True, 'Yes')]
    spoiler = models.BooleanField(default=False,null=True, choices = spoiler_choices)
    content = RichTextField(null=True,default=' ')
    type = models.CharField(max_length=10,default="book")
    slug = models.SlugField(max_length= 300,null=True, blank = True, unique=True)


    def __str__(self):
        return f'{self.title}|{self.creator}'
    def save(self, *args, **kwargs):
        self.slug = slugify(self.title + str(self.posted))
        super(BookList,self).save(*args, **kwargs)

class BookGenre(models.Model):
    name = models.CharField(max_length=150)

    def __str__(self):
        return self.name


class List(models.Model):
    title = models.CharField(max_length=120)
    genre = models.ManyToManyField('Genre')
    creator = models.ForeignKey(User,on_delete=models.SET_NULL,blank=True, null=True)
    posted = models.DateTimeField(auto_now_add=True)
    content = RichTextField(null=True,default=' ')
    type = models.CharField(max_length=10,default="Movie")
    spoiler_choices = [(False, 'No'),(True, 'Yes')]
    spoiler = models.BooleanField(default=False,null=True, choices = spoiler_choices)
    slug = models.SlugField(max_length= 300,null=True, blank = True, unique=True)


    def __str__(self):
        return f'{self.title}|{self.creator}'
    def save(self, *args, **kwargs):
        self.slug = slugify(self.title + str(self.posted))
        super(List,self).save(*args, **kwargs)


class Genre(models.Model):
    name = models.CharField(max_length=150)

    def __str__(self):
        return self.name


class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, blank=True)
    bio = models.TextField(max_length=500, blank=True)
    location = models.CharField(max_length=30, blank=True)
    birth_date = models.DateField(null=True, blank=True)
    profile_pic = models.ImageField(blank=True, default='', upload_to='profiles_pics')
    fav_music_genre = models.ManyToManyField('MusicGenre')
    fav_Book_genre = models.ManyToManyField('BookGenre')
    fav_movie_genre = models.ManyToManyField('Genre')
    
    def __str__(self):
        return self.user.username + " | bio : " + self.bio

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)

@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    instance.profile.save()
解决方案

步骤1:导入必要模块

在视图文件中导入相关模型与用户验证模块:

from django.shortcuts import render
from .models import List, MusicList, BookList, Profile

步骤2:编写all视图函数

def all(request):
    # 初始化查询集,默认显示全部内容
    movie_lists = List.objects.all()
    music_lists = MusicList.objects.all()
    book_lists = BookList.objects.all()

    # 处理登录用户的流派过滤逻辑
    if request.user.is_authenticated:
        try:
            profile = request.user.profile
            # 获取用户收藏的各流派ID列表
            fav_movie_ids = profile.fav_movie_genre.values_list('id', flat=True)
            fav_music_ids = profile.fav_music_genre.values_list('id', flat=True)
            fav_book_ids = profile.fav_Book_genre.values_list('id', flat=True)

            # 过滤电影列表:保留包含至少一个收藏流派的帖子
            if fav_movie_ids:
                movie_lists = List.objects.filter(genre__in=fav_movie_ids).distinct()
            # 过滤音乐列表
            if fav_music_ids:
                music_lists = MusicList.objects.filter(genre__in=fav_music_ids).distinct()
            # 过滤书籍列表
            if fav_book_ids:
                book_lists = BookList.objects.filter(genre__in=fav_book_ids).distinct()

        except Profile.DoesNotExist:
            # 信号已自动创建Profile,此分支为兜底处理
            pass

    # 将结果传递给模板
    context = {
        'movie_lists': movie_lists,
        'music_lists': music_lists,
        'book_lists': book_lists,
    }
    return render(request, 'your_template.html', context)

核心逻辑说明

  1. values_list('id', flat=True):提取收藏流派的ID列表,用于后续过滤查询。
  2. filter(genre__in=...):Django多对多字段过滤语法,筛选出流派匹配用户收藏的帖子。
  3. .distinct():避免同一帖子因匹配多个收藏流派而重复显示。
  4. 默认逻辑:未登录/无收藏流派时显示全部内容,可根据需求修改(比如提示用户登录或选择流派)。

模板使用示例

在模板中遍历过滤后的结果:

<h2>推荐电影</h2>
{% for movie in movie_lists %}
    <div>{{ movie.title }} - {{ movie.genre.all|join:", " }}</div>
{% empty %}
    <p>暂无匹配的电影内容</p>
{% endfor %}

<h2>推荐音乐</h2>
{% for music in music_lists %}
    <div>{{ music.title }} - {{ music.genre.all|join:", " }}</div>
{% empty %}
    <p>暂无匹配的音乐内容</p>
{% endfor %}

<h2>推荐书籍</h2>
{% for book in book_lists %}
    <div>{{ book.title }} - {{ book.genre.all|join:", " }}</div>
{% empty %}
    <p>暂无匹配的书籍内容</p>
{% endfor %}

内容的提问来源于stack exchange,提问作者Ayat Rahman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 23:25:18