我有一个带有ManyToManyField
的模特
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
class Skill(models.Model):
def __str__(self):
en_translation = self.translations.filter(language__contains='en').first()
if en_translation:
return en_translation.name
return "No english translations"
class SkillTranslation(models.Model):
language = models.CharField(max_length=5)
name = models.CharField(max_length=100)
skill = models.ForeignKey(Skill, on_delete=models.CASCADE, related_name='translations')
def __str__(self):
return self.name
class SkillOwnership(models.Model):
skill = models.ForeignKey(Skill, on_delete=models.CASCADE, related_name='skill_ownerships')
owner = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='skill_ownerships')
def __str__(self):
return f'{str(self.owner.email)} < {str(self.skill)}'
class Meta:
unique_together = ['skill', 'owner']
并通过非优化的方式对其进行搜索:
def get_queryset(self):
result = CustomUser.objects.all()
if 'skills' in self.request.query_params:
skill_ids = [int(sid) for sid in self.request.query_params.get('skills').split(',')]
for skill_id in skill_ids:
result = result.filter(skill_ownerships__skill_id=skill_id).distinct()
return result.exclude(pk=self.request.user.pk)
我需要通过对数据库的一次查询来获得相同的结果。我需要找到skill_ids
数组中所有技能的所有用户。
UPD
我的get_queryet
方法现在看起来像
def get_queryset(self):
not_reviewed = bool(int(self.request.query_params.get('not_reviewed', '0')))
result = self.request.user.find_in_distance(int(self.request.query_params.get('distance', '0')))
if not_reviewed:
result = result.exclude(income_likes__like_from__id=self.request.user.id)
if 'skills' in self.request.query_params:
skill_ids = [int(sid) for sid in self.request.query_params.get('skills').split(',')]
skills_ownerships = SkillOwnership.objects.filter(skill_id__in=skill_ids).annotate(skill_count=Count('*')).values('owner').distinct()
result = result.annotate(user_skill_count=Subquery(skills_ownerships)).filter(user_skill_count=len(skill_ids))
return result.exclude(pk=self.request.user.pk).exclude(income_reports__author=self.request.user)
在return
result
的查询之前,如下所示:
SELECT "accounts_customuser"."id", "accounts_customuser"."password", "accounts_customuser"."last_login", "accounts_customuser"."is_superuser", "accounts_customuser"."email", "accounts_customuser"."username", "accounts_customuser"."first_name", "accounts_customuser"."last_name", "accounts_customuser"."company", "accounts_customuser"."job", "accounts_customuser"."linkedin_username", "accounts_customuser"."twitter_username", "accounts_customuser"."facebook_username", "accounts_customuser"."vk_username", "accounts_customuser"."instagram_username", "accounts_customuser"."website", "accounts_customuser"."about_me", "accounts_customuser"."location"::bytea, "accounts_customuser"."preferred_distance", "accounts_customuser"."fcm_token", "accounts_customuser"."is_active", "accounts_customuser"."is_staff", (SELECT DISTINCT U0."owner_id" FROM "pro_skillownership" U0 WHERE U0."skill_id" IN (80, 32) GROUP BY U0."id") AS "user_skill_count" FROM "accounts_customuser" WHERE (SELECT DISTINCT U0."owner_id" FROM "pro_skillownership" U0 WHERE U0."skill_id" IN (80, 32) GROUP BY U0."id") = 2
答案 0 :(得分:0)
skills = SkillOwnership.objects.filter(
skill_id__in=skill_ids, owner_id=OuterRef('pk')).values('skill_id')
users = CustomUser.objects.annotate(user_skill_count=Count(Subquery(skills ))).\
filter(user_skill_count=len(skill_ids))