使用带有外键的 Q 对象定义 django 查询集

Posted

技术标签:

【中文标题】使用带有外键的 Q 对象定义 django 查询集【英文标题】:Defining django queryset with Q objects with foreign key 【发布时间】:2013-02-27 23:12:42 【问题描述】:

示例模型:

class Book(models.Model):
    title = models.TextField()

class Author(models.Model):
    book = models.ForeignKey(Book)
    name = models.CharField(max_length=50)

还有一些示例数据:

Book:
id  title
1   test111
2   test222
3   test333
4   test444

Author:
book_id  name
1        test111
1        test222
2        test222
2        test333
3        test111
3        test333
4        test111
4        test333

我想获取作者姓名包含“111”和“333”的所有书籍(所以所有至少有 2 个作者的书籍:第一个名称为 111,第二个名称为 333)

我可以通过使用链式查询来达到这个目标:

books = Book.objects.filter(author__name__icontains="111").filter(author__name__icontains="333")

返回两本书,id:3 和 4

有没有办法通过使用 Q 对象达到上述目标?

【问题讨论】:

这里模型 Book 没有模型 Author 的外键。那么如何使用作者姓名进行过滤呢? 在 shell 上调用 Book.objects.filter(author__name__icontains="111") 时,django 在 (book.id = author.book_id) 上调用带有 INNER JOIN 的 sql 查询 【参考方案1】:

你可以结合reduce和Q,见The power of django’s Q objects帖子。

from django.db.models import Q
import operator
auths = [ "111", "333" ]
query = reduce(operator.and_, [ Q(author__name__icontains=x) for x in auths ] )
books = Book.objects.filter( query )

【讨论】:

【参考方案2】:

这个是动态授权列表:

pk_list = qs.values_list('pk', flat=True)  # i.e [] or [1, 2, 3]

if len(pk_list) == 0:
    Book.objects.none()

else:
    q = None
    for pk in pk_list:
        if q is None:
            q = Q(pk=pk)
        else:
            q = q | Q(pk=pk)

    Book.objects.filter(q)

【讨论】:

以上是关于使用带有外键的 Q 对象定义 django 查询集的主要内容,如果未能解决你的问题,请参考以下文章

带有 Q 对象的查询集的 Django 优化

带有外键的 django 自定义表单验证

django 插入外键值思路

如何使用具有外键的模型进行 Q 查询?

为什么在Django上使用bulk_create插入带有外键的数据会返回“属性对象不可调用”?

django 查询具有外键的模型,检查该外键的属性