如何在Django中跨三个关联模型查询用户所属全部Campaign
问题描述
我正在使用Django,希望了解如何通过三个关联模型获取对象。以下是我的模型代码:
class Participant(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) is_leader = models.BooleanField(default=False) team = models.ForeignKey(Team, on_delete=models.CASCADE, null=True, related_name="participants") application_date = models.DateField(auto_now_add=True, null=True) resolution_date = models.DateField(null=True, blank=True) accepted = models.BooleanField(default=False) class Team(models.Model): name = models.TextField(default="") is_public = models.BooleanField(default=False) institution = models.ForeignKey(Institution, on_delete=models.CASCADE, null=True, related_name='teams') campaign = models.ForeignKey(Campaign, on_delete=models.CASCADE, null=True, related_name='teams') class Campaign(models.Model): name = models.TextField(default="") description = models.TextField(default="") initial_date = models.DateTimeField(auto_now_add=False, null=True, blank=True) end_date = models.DateTimeField(auto_now_add=False, null=True, blank=True) qr_step_enabled = models.BooleanField(default=True) image_resolution = models.IntegerField(default=800) sponsor = models.ForeignKey(Sponsor, on_delete=models.CASCADE, null=True, related_name='campaigns')
我已通过request获取到user对象,想要获取该用户所属的全部Campaign。原本我使用循环实现:
user = request.user participants = user.participant_set.all() for participant in participants: participant.team.campaign.name
请问是否可以通过跨模型查询实现该需求?用户可拥有多个Participant,每个Participant对应一个Team,每个Team对应一个Campaign。
解决方案
当然可以通过Django的跨模型关联查询直接实现,不需要循环遍历,还能避免N+1数据库查询问题,提升效率。以下是几种可行方式:
方式一:从Campaign模型反向关联查询
利用Django的双下划线__实现跨模型筛选,直接定位到关联当前用户的Campaign:
user = request.user campaigns = Campaign.objects.filter(teams__participants__user=user).distinct()
teams__participants__user表示:Campaign关联的Team → Team关联的Participant → Participant关联的User等于当前用户.distinct()用于去重,避免同一个Campaign因用户多个Participant关联而重复出现
方式二:从User模型正向关联查询
从当前用户出发,通过关联的Participant、Team反向定位到Campaign:
user = request.user # 获取完整的Campaign对象 campaigns = Campaign.objects.filter(id__in=user.participant_set.values_list('team__campaign__id', flat=True)).distinct() # 若只需获取Campaign的ID,可直接用values_list campaign_ids = user.participant_set.values_list('team__campaign__id', flat=True).distinct()
方式三:优化原循环逻辑(可选)
如果需要保留循环处理逻辑,可通过select_related预加载关联对象,减少数据库查询次数:
user = request.user # 提前预加载team和campaign,仅发起1次数据库查询 participants = user.participant_set.select_related('team__campaign').all() for participant in participants: print(participant.team.campaign.name)
内容的提问来源于stack exchange,提问作者RaimundoDiaz
相关产品推荐
相关产品推荐

