我有以下模型用于存储两个用户之间的双向关系。记录总是插入在较小的用户标识为user_a而较大的用户标识为user_b的位置。
是否有一种方法可以根据参考用户ID大于还是小于另一个用户ID来检索属于参考用户的所有记录和状态的正确值(如果为user_a,则将否定转换应用于Relationship_type)? / p>
也许有两个单独的查询,一个查询中的参考用户= user_a,另一个查询中的参考用户= user_b,然后进行联接?
class Relationship(models.Model):
RELATIONSHIP_CHOICES = (
(0, 'Blocked'),
(1, 'Allowed'),
(-2, 'Pending_A'),
(2, 'Pending_B'),
(-3, 'Blocked_A'),
(3, 'Blocked_B'),
)
user_a = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, related_name='user_a',null=True)
user_b = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, related_name='user_b',null=True)
relationship_type = models.SmallIntegerField(choices=RELATIONSHIP_CHOICES, default=0)
我要实现的SQL查询:
(SELECT user_b as user_select, -relationship_type as type_select WHERE user_a='reference_user') UNION (SELECT user_a as user_select, relationship_type as type_select WHERE user_b='reference_user')
答案 0 :(得分:2)
鉴于您拥有用户user_id
的ID,可以使用以下过滤条件:
from django.db.models import Q
Relationship.objects.filter(Q(user_a_id=user_id) | Q(user_b_id=user_id))
如果您有一个CustomUser
对象user
,则几乎相同:
from django.db.models import Q
Relationship.objects.filter(Q(user_a=user) | Q(user_b=user))
如果您要获取给定类型的Relationship
,我们可以执行以下操作:
from django.db.models import Q
rel_type = 2 # example rel_type
Relationship.objects.filter(
Q(user_a=user, relationship_type=rel_type) |
Q(user_b=user, relationship_type=-rel_type)
)
因此,我们在此处检索给定用户Relationship
和user_a
的{{1}}个对象,或给定用户relationship_type=2
和{{1}的Relationship
对象}}。
我们可以注释查询集,然后进行合并,例如:
user_b
尽管我不知道这是否是一个好主意:注释不是“可写的”(因此您无法更新它们)。
最好实现某种“代理对象”,它可以交换relationship_type=-2
和qs1 = Relationship.objects.filter(
user_a=user, relationship_type=rel_type
).annotate(
user_select=F('user_b'),
rel_type=F('relationship_type')
)
qs2 = Relationship.objects.filter(
user_a=user, relationship_type=rel_type
).annotate(
user_select=F('user_a'),
rel_type=-F('relationship_type')
)
qs = qs1.union(qs2)
,并取反user_a
类型,从而能够像是真实的user_b
对象。
答案 1 :(得分:1)
正如您所说,number_format
中的id总是小于user_a
。因此,如果您使用user_b
查询,则应该始终获取引用,其中引用中的user_b=user
总是比其他user_id
高。因此,我认为您可以使用以下查询集:
user_id