简体   繁体   English

Django ORM:筛选外键属性的元组

[英]Django ORM: filter for tuples of foreign key attributes

I'm writing a matching service that will match you with profiles based on overlapping expertise. 我正在编写一项匹配服务,该服务将根据重叠的专业知识为您提供配置文件。 Eg if you are REQUESTING python expertise, it will match you with folks OFFERING python expertise. 例如,如果您需要python专业知识,它将与您提供python专业知识的人士相匹配。

I'm having trouble determining how to structure that query with the Django ORM. 我在确定如何使用Django ORM构造查询时遇到麻烦。

Setup 设定

I have models: 我有模特:

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)

Data 数据

I've got data that essentially looks like the following: 我得到的数据基本上如下所示:

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

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

Obviously Wrong Attempt 明显错误的尝试

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()]
)

I'm essentially looking for the ability to combine boolean AND and boolean OR in the query. 我本质上是在寻找在查询中组合布尔AND和布尔OR的能力。

In a different technology, I'd... 我会用另一种技术...

In SQL I'd do something along the lines of: 在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)

Expected behavior 预期行为

>>> 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>]

For complex queries Django offers Q objects 对于复杂的查询,Django提供了Q对象

So you might query that table with Q objects like; 因此,您可以使用以下Q对象查询该表:

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

The | | is the OR and the & is self explanatory. OR ,而&是自我解释。 You can also do ~Q for NOT style queries. 你也可以做~QNOT样式的查询。

select_related , if you've not come across it, makes a more efficient query for related objects. select_related ,如果您还没有碰到它的话,可以对相关对象进行更有效的查询。 You can read more about that here; 您可以在此处了解更多信息。 https://medium.com/@lucasmagnum/djangotip-select-prefetch-related-e76b683aa457 https://medium.com/@lucasmagnum/djangotip-select-prefetch-related-e76b683aa457

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM