3

我有一个事件对象,除此之外还有其他对象Notes与 具有通用关系Event,并且没有活动字段。现在我希望能够编写一个查询,它排除所有Events活动字段Notes为 False 的地方。所以我尝试执行以下操作。

queryset = Event.objects.all()
filters = (
        Q(content_type__model='notes') &
        Q(note__active=False)
    )
queryset = queryset.exclude(filters)

这不起作用,因为它单独运行查询,并且当它尝试为没有 content_object 或不是 type 的项目执行时Notes,它失败并给出以下错误:

AttributeError 'GenericRelation' object has no attribute 'field'.

class Event(models.Model):
    content_type = models.ForeignKey(ContentType, null=True, blank=True)
    object_id = models.PositiveIntegerField(null=True, blank=True)
    content_object = GenericForeignKey('content_type', 'object_id')

class Notes(models.Model):
    active = models.BooleanField(default=True)
    event_log = GenericRelation(
        'Event',
        related_query_name='note'
    )
4

2 回答 2

3

使用 Django ORM 的常用方法是使用子查询:

Event.objects.exclude(
    content_type=note_content_type,
    object_id__in=Notes.objects.filter(active=False),
)

可悲的是,这可以用连接而不是子查询在 SQL 中表达,但 ORM 并没有那么容易。

在某些情况下,PostgreSQL 的查询计划器可以将子查询优化为哈希半联接,因此不要在未对数据进行基准测试的情况下优先考虑原始 SQL 来忽略子查询。

于 2017-01-19T00:56:37.953 回答
1

另一种方法是使用条件表达式,例如

from django.db import models
queryset = Event.objects.all()
queryset = queryset.annotate(
    is_inactive_note=models.Case(
        models.When(
            content_type__model='notes',
            note__active=False,
            then=models.Value(True),
        ),
        default=models.Value(False),
        output_field=models.BooleanField(),
    )
).filter(is_inactive_note=False)
于 2018-08-08T15:35:29.547 回答