在列表理解中使用 Q 对象
Using Q object in list comprehension
我有以下代码:
def get_elements(self, obj):
book_elements = Element.objects.filter(book__pk=obj.id)
elements = Element.objects.filter( (Q(book__pk=obj.id) | Q(theme__pk=obj.theme_id)), ~Q(pk__in = [o.element_id for o in book_elements if o.element_id]))
serializer = GetElementSerializer(elements, context=self.context, many=True)
elements 变量是使用 Q 对象实现的查询。但是,Q(book__pk=obj.id)
和 book_elements
引用完全相同的一组值。我如何在列表理解中引用 Q(book__pk=obj.id)
以避免不得不 运行 2 查询。类似于以下内容:
def get_elements(self, obj):
elements = Element.objects.filter( (Q(book__pk=obj.id) | Q(theme__pk=obj.theme_id)), ~Q(pk__in = [o.element_id for o in Q(book__pk=obj.id) if o.element_id]))
serializer = GetElementSerializer(elements, context=self.context, many=True)
我要求的元素模型:
class Element(models.Model):
name = models.CharField(max_length=100)
pub_date = models.DateTimeField('date published', auto_now_add=True)
mod_date = models.DateTimeField('modified date', auto_now=True)
book = models.ForeignKey(Book, blank=True, null=True, related_name='elements')
book_part = models.ForeignKey(BookPart)
theme = models.ForeignKey(Theme, blank=True, null=True, related_name='elements')
element = models.ForeignKey('self', blank=True, null=True, related_name='parent')
def __str__(self):
return self.name
感谢任何帮助!
这里是一个带子查询的单查询解决方案:
elements = Element.objects.filter(
(Q(book__pk=obj.id) | Q(theme__pk=obj.theme_id)),
~Q(pk__in = Element.objects.filter(
book__pk=obj.id,
element__isnull=False
).values_list('element', flat=True)
)
)
这只会访问数据库一次。
顺便说一句,在阅读了您实际想要实现的目标之后:
get me all the elements, with a book_id or theme_id, that equals the
book id & theme id for this book, excluding elements that also have a
FK relationship to another element in this book
以 ORM 方式,我认为这也可以这样实现:
elements = Element.objects \
.filter(Q(book_id=book.id)|Q(theme_id=book.theme_id)) \
.exclude(element__in=book.elements.all()) #not tested, if throws an error transform it into: book.elements.values_list('id', flat=True)
同样,这只会访问数据库一次,因为 querysets
是懒惰的,而 Django
足够聪明,可以在将它们拆分为另一个 queryset
时将它们转换为子查询.
您应该可以像这样在一次查询中完成。它利用了反向关系。
elements = Element.objects.filter(
Q(book=obj) | Q(theme__pk=obj.theme_id)
).exclude(
book=obj, element__isnull=False
)
我有以下代码:
def get_elements(self, obj):
book_elements = Element.objects.filter(book__pk=obj.id)
elements = Element.objects.filter( (Q(book__pk=obj.id) | Q(theme__pk=obj.theme_id)), ~Q(pk__in = [o.element_id for o in book_elements if o.element_id]))
serializer = GetElementSerializer(elements, context=self.context, many=True)
elements 变量是使用 Q 对象实现的查询。但是,Q(book__pk=obj.id)
和 book_elements
引用完全相同的一组值。我如何在列表理解中引用 Q(book__pk=obj.id)
以避免不得不 运行 2 查询。类似于以下内容:
def get_elements(self, obj):
elements = Element.objects.filter( (Q(book__pk=obj.id) | Q(theme__pk=obj.theme_id)), ~Q(pk__in = [o.element_id for o in Q(book__pk=obj.id) if o.element_id]))
serializer = GetElementSerializer(elements, context=self.context, many=True)
我要求的元素模型:
class Element(models.Model):
name = models.CharField(max_length=100)
pub_date = models.DateTimeField('date published', auto_now_add=True)
mod_date = models.DateTimeField('modified date', auto_now=True)
book = models.ForeignKey(Book, blank=True, null=True, related_name='elements')
book_part = models.ForeignKey(BookPart)
theme = models.ForeignKey(Theme, blank=True, null=True, related_name='elements')
element = models.ForeignKey('self', blank=True, null=True, related_name='parent')
def __str__(self):
return self.name
感谢任何帮助!
这里是一个带子查询的单查询解决方案:
elements = Element.objects.filter(
(Q(book__pk=obj.id) | Q(theme__pk=obj.theme_id)),
~Q(pk__in = Element.objects.filter(
book__pk=obj.id,
element__isnull=False
).values_list('element', flat=True)
)
)
这只会访问数据库一次。
顺便说一句,在阅读了您实际想要实现的目标之后:
get me all the elements, with a book_id or theme_id, that equals the book id & theme id for this book, excluding elements that also have a FK relationship to another element in this book
以 ORM 方式,我认为这也可以这样实现:
elements = Element.objects \
.filter(Q(book_id=book.id)|Q(theme_id=book.theme_id)) \
.exclude(element__in=book.elements.all()) #not tested, if throws an error transform it into: book.elements.values_list('id', flat=True)
同样,这只会访问数据库一次,因为 querysets
是懒惰的,而 Django
足够聪明,可以在将它们拆分为另一个 queryset
时将它们转换为子查询.
您应该可以像这样在一次查询中完成。它利用了反向关系。
elements = Element.objects.filter(
Q(book=obj) | Q(theme__pk=obj.theme_id)
).exclude(
book=obj, element__isnull=False
)