我有两个模型:
class Subscription(models.Model):
name = models.CharField(max_length=100, unique=True)
class Email(models.Model):
email = models.EmailField(unique=True)
subscriptions = models.ManyToManyField(Subscription)
is_confirmed = models.BooleanField(default=False)
我需要通过Django Orm模拟SQL查询
select * from newsletter_subscription ss
left join newsletter_mail_subscriptions ms
on ss.id = ms.subscription_id and ms.mail_id = <mail_id>;
所以我可以通过获取可用订阅的整个列表来查看邮件是否已订阅每个订阅
我需要类似FilteredRelated的内容:
q = Subscription.objects.annotate(
is_subscribe=FilteredRelation(
'mail_subscriptions', condition=Q(mail_subscriptions__mail_id=10)
)
)
但是FilteredRelation不支持跨越关系字段的条件
答案 0 :(得分:1)
根本不需要使用FilteredRelation
来执行此操作,您可以这样写:
Subscription.objects.filter(
email__id=mail_id
)
使用 mail_id
您要过滤的Email
对象的ID。
Django将构建如下查询:
SELECT subscription.id, subscription.name
FROM subscription
INNER JOIN email_subscriptions
ON subscription.id = email_subscriptions.subscription_id
WHERE email_subscriptions.email_id = email_id
无论如何都不需要使用LEFT OUTER JOIN
,因为您检查mail_id
是否是特定的id
,因此INNER JOIN
将得到相同的集合。
请注意,您使用的是ManyToManyField
,并且Django在两个实体之间创建了一个表,但是您不能访问该表,除非您使用参数through
[Django-doc]指定一个模型。
您还可以用Subscription
来注释is_subscribed
,例如:
from django.db.models import Exists, OuterRef
Subscription.objects.annotate(
is_subscribed=Exists(
Email.subscriptions.through.objects.filter(
subscription_id=OuterRef('id'),
mail_id=email_id
)
)
)
这将导致如下查询:
SELECT subscription.*,
EXISTS(
SELECT U0.id, U0.email_id, U0.subscription_id
FROM email_subscriptions U0
WHERE U0.subscription_id = subscription.id AND U0.mail_id = email_id
) AS is_subscribed
FROM subscription