Django ORM:过滤外键属性的元组

Django ORM: filter for tuples of foreign key attributes

我正在编写一项匹配服务,可以根据重叠的专业知识为您匹配个人资料。例如。如果您正在请求 python 专业知识,它会将您与提供 python 专业知识的人相匹配。

我无法确定如何使用 Django ORM 构造该查询。

设置

我有模特:

class Profile(models.Model):
    pass

class Expertise(models.Model):
    profile = db.ForeignKey('profile', on_delete=models.CASCADE)
    name = db.CharField(choices=[(1, 'python'), (2, 'javascript'), (3, 'golang')], max_length =255)
    direction = db.CharField(choices=[('offered', 'offered'), ('requested', 'requested')], max_length = 255)

数据

我得到的数据基本上如下所示:

# setup some fields
profile = Profile()
profile.save()

Expertise(profile=profile, name=1, direction='requested').save()
Expertise(profile=profile, name=2, direction='offered').save()

显然是错误的尝试

Profile.objects.filter(
   expertise__name__in = [e.name for e in profile.expertise_set()]
   expertise__direction__in = [e.direction for e in profile.expertise_set()]
)

我本质上是在寻找在查询中组合布尔 AND 和布尔 OR 的能力。

在不同的技术中,我会...

在 SQL 中,我会按照以下方式做一些事情:

SELECT * FROM app_profiles JOIN app_expertise on app_profiles.id = app_expertise.app_profiles_id 
WHERE 
   (app_expertise.direction = 'offered' AND app_expertise.name = 1) OR
   (app_expertise.direction = 'requested' AND app_expertise.name = 2)

预期行为

>>> maus = Profile.objects.get_or_create(name='Maus')[0]
>>> kungphu = Profile.objects.get_or_create(name='kungphu')[0]
>>> strange = Profile.objects.get_or_create(name='Dr. Strange')[0]
>>> thanos = Profile.objects.get_or_create(name='thanos')[0]
>>> 
>>> # maus offers golang and requests python
>>> Expertise.objects.get_or_create(
...     profile=maus, 
...     name=Expertise.NAME_PYTHON, 
...     direction=Expertise.DIRECTION_REQUESTED,
... )[0]
<Expertise: Python (Requested by Maus)>
>>> Expertise.objects.get_or_create(
...     profile=maus, 
...     name=Expertise.NAME_GOLANG, 
...     direction=Expertise.DIRECTION_OFFERED,
... )[0]
<Expertise: Golang (Offered by Maus)>
>>> # kungphu offers python and requests golang, they will match 
>>> # with mous both because of golang and python compatibility
>>> Expertise.objects.get_or_create(
...     profile=kungphu, 
...     name=Expertise.NAME_PYTHON, 
...     direction=Expertise.DIRECTION_OFFERED,
... )[0]
<Expertise: Python (Requested by kungphu)>
>>> Expertise.objects.get_or_create(
...     profile=kungphu, 
...     name=Expertise.NAME_GOLANG, 
...     direction=Expertise.DIRECTION_REQUESTED,
... )[0]
<Expertise:Golang (Requested by kungphu)>
>>> # Doctor Strange is trying to learn golang, he will match with maus as 
>>> # a result.
>>> Expertise.objects.get_or_create(
...     profile=kungphu, 
...     name=Expertise.NAME_GOLANG, 
...     direction=Expertise.DIRECTION_REQUESTED,
... )[0]
<Expertise:Golang (Requested by strange)>
>>> 
>>> # Thanos both offers and requests Python, because balance, I guess.
>>> Expertise.objects.get_or_create(
...     profile=thanos, 
...     name=Expertise.NAME_PYTHON, 
...     direction=Expertise.DIRECTION_REQUESTED,
... )[0]
<Expertise: Python (Requested by thanos)>
>>> Expertise.objects.get_or_create(
...     profile=thanos, 
...     name=Expertise.NAME_PYTHON, 
...     direction=Expertise.DIRECTION_OFFERED,
... )[0]
<Expertise: Python (Offered by thanos)>
>>> 
>>> # maus has requested Python, thanos and kungphu have offered it
>>> # maus has offered golang, dr. strange and kungphu have requested it.
>>> maus.find_matches()
[<Profile: kungphu>, <Profile: thanos>, <Profile: strange>]

对于复杂的查询,Django 提供 Q objects

因此您可以使用 Q 对象查询 table;

Expertise.objects.select_related('profile').filter(
    (Q(direction='offered') & Q(name=1)) | (Q(direction='requested') & Q(name=2))
)

|OR& 是不言自明的。您还可以为 NOT 样式查询执行 ~Q

select_related,如果你没有遇到过它,对相关对象进行更有效的查询。您可以在此处阅读更多相关信息; https://medium.com/@lucasmagnum/djangotip-select-prefetch-related-e76b683aa457