Skip to main content
 首页 » 编程设计

python之Django 用交集数注释查询集

2024年12月31日28zhenyulu

Djangonauts,我需要挖掘你的大脑。

简而言之,我有以下三个模型:

class Location(models.Model): 
    name = models.CharField(max_length=100) 
 
 
class Profile(models.Model): 
    locations_of_interest = models.ManyToManyField(Location) 
 
 
class Question(models.Model): 
    locations = models.ManyToManyField(Location) 

我想找到感兴趣的位置与为特定问题指定的位置相交的所有配置文件。这很简单:

question = Question.objects.first() 
 
matching_profiles = Profile.objects.filter( 
    locations_of_interest__in=question.locations.all() 
) 

但除此之外,我还想知道位置重叠到什么程度。

在普通的 python 中,我可以做这样的事情:

question_location_names = [l['name'] for l in question.locations.all()] 
 
for profile in matching_profiles: 
    profile_location_names = [l['name'] for l in profile.locations_of_interest.all()] 
    intersection = set(question_location_names).intersection(profile_location_names) 
    intersection_count = len(list(intersection)) 
    # then proceed with this number 

但是,在我看来,如果可能的话,直接在数据库中进行操作似乎更有利。

长话短说

所以我的问题是:

有没有办法用这个交集计数来注释配置文件查询集,并以这种方式在数据库中进行操作?

我已经尝试了几种方法,但我认为它们对阅读本文并可能知道答案的人没有帮助。

请您参考如下方法:

您可以使用 .annotate(..) 执行此操作,此操作使用 locations_of_interest 数字上的 Count(..):

<b>from django.db.models import Count</b> 
 
matching_profiles = Profile.objects.filter( 
    locations_of_interest__in=question.locations.all() 
)<b>.annotate( 
    locnom=Count('locations_of_interest') 
)</b>

现在每个 matching_profiles 实例都有一个名为 locnom 的属性,其中包含与过滤器匹配的兴趣位置的数量。

请注意,没有这些位置的 Profile 不会出现在查询集中,并且每个 Profile 最多出现一次。

编辑:计算多个相关的非重叠(!)字段

您可以通过使用 distinct=True 计算非重叠连接来扩展此方法:

from django.db.models import Count 
 
matching_profiles = Profile.objects.filter( 
    locations_of_interest__in=question.locations.all(), 
    <b>industries_of_interest__in=question.industries.all()</b> 
)<b>.annotate( 
    locnom=Count('locations_of_interest'<b>, distinct=True</b>)<b>, 
    indnom=Count('industries_of_interest', distinct=True)</b> 
)</b>

但是请注意,此方法通常随 JOIN 的数量呈指数扩展,因此如果您要添加,这通常不可可扩展数十个我们数百个注释。