我有两个模型:
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不支持跨越关系字段的条件
请您参考如下方法:
对于 FilteredRelation 根本不需要这样做,您可以这样写:
Subscription.objects.filter(
<b>email__id=</b><i>mail_id</i>
)
使用 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 = <i>email_id</i>
无论如何都不需要使用 LEFT OUTER JOIN,因为您检查 mail_id 是否是特定的 id,因此 code>INNER JOIN 将产生相同的集合。
请注意,您使用了 ManyToManyField,并且 Django 在两个实体之间创建了一个表,但您无法访问该表,除非您指定一个带有 through [Django-doc] 的模型。参数。
您还可以使用 is_subscribed 注释 Subscription,例如:
from django.db.models import Exists, OuterRef
Subscription.objects.annotate(
is_subscribed=Exists(
Email.subscriptions.through.objects.filter(
subscription_id=OuterRef('id'),
mail_id=<i>email_id</i>
)
)
)
这会产生如下查询:
SELECT subscription.*,
<b>EXISTS(</b>
SELECT U0.id, U0.email_id, U0.subscription_id
FROM email_subscriptions U0
WHERE U0.subscription_id = subscription.id AND U0.mail_id = <i>email_id</i>
<b>) AS is_subscribed</b>
FROM subscription
