Django ORM QuerySet 通过字段交集

发布于 2024-10-10 02:46:04 字数 293 浏览 0 评论 0原文

这些是我拥有的(伪)模型。

Blog:
  name
  etc...

Article:
  name
  blog
  creator
  etc

User (as per django.contrib.auth)

所以我的问题是这样的:我有两个用户。我想要获取两个用户在同一个博客(无论是哪个博客)上发布的所有文章。我不能简单地过滤两个用户的文章模型,因为这会产生两个用户创建的文章集。显然不是我想要的。但是我可以以某种方式过滤以获得对象的字段在两个查询集之间匹配的所有文章吗?

These are the (pseudo) models I've got.

Blog:
  name
  etc...

Article:
  name
  blog
  creator
  etc

User (as per django.contrib.auth)

So my problem is this: I've got two users. I want to get all of the articles that the two users published on the same blog (no matter which blog). I can't simply filter the Article model by both users, because that would yield the set of Articles created by both users. Obviously not what I want. but can I filter somehow to get all of the articles where a field of the object matches between the two querysets?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

陪你到最终 2024-10-17 02:46:04

对于练习 Django 的 ORM 来说,这是一个很好的问题:-)

根据提前知道哪些参数,有几种方法可以解决这个问题。

场景 1:您了解用户和特定博客

如果您有一个特定的博客,并且想要简单地查找任一作者撰写的所有文章,您可以使用 Q 对象。我认为这不是您的场景,但为了以防万一,我将其放在这里:

from django.db.models import Q
Article.objects.filter(Q(creator=user1) | Q(creator=user2), blog=some_blog_instance)

场景 2:您只知道用户

如果您想查找两个用户都发布过的所有博客,并且然后想要找到他们在这些博客中发布了哪些文章,您需要从 Blog 模型开始:

from django.db.models import Q

# Find all blogs where both user1 and user2 have written articles
blogs = Blog.objects.filter(article__creator=user1).\
        filter(article__creator=user2).distinct()

# Now find which articles those were
for blog in blogs:
    articles = blog.article_set.filter(Q=(creator=user1) | Q=(creator=user2))

根据 Paulo 的评论进行编辑:

这是一组我认为与OP 的伪代码,它演示了上述代码的工作原理(至少在 sqlite3 和 postgres 上):

from django.db import models
from django.contrib.auth.models import User

class Blog(models.Model):
    name = models.CharField(max_length=128)

class Article(models.Model):
    name = models.CharField(max_length=128)
    blog = models.ForeignKey(Blog)
    creator = models.ForeignKey(User)

然后是 user1 和 user2 在 blog2 上写文章的一些数据:

u1 = User.objects.create(username='u1')
u2 = User.objects.create(username='u2')

b1 = Blog.objects.create(name='b1')
b2 = Blog.objects.create(name='b2')
b3 = Blog.objects.create(name='b3')

b1_art1 = Article.objects.create(name='b1_art1', blog=b1, creator=u1)
b2_art1 = Article.objects.create(name='b2_art1', blog=b2, creator=u1)
b2_art2 = Article.objects.create(name='b2_art2', blog=b2, creator=u2)

查询:

[b.name for b in Blog.objects.filter(article__creator=user1).\
    filter(article__creator=user2).distinct()]

产生:

[b2]

SQL 是(我的测试 django 应用程序名为 foo) :

SELECT "foo_blog"."id", "foo_blog"."name" 
FROM "foo_blog" 
INNER JOIN "foo_article" ON ("foo_blog"."id" = "foo_article"."blog_id") 
INNER JOIN "foo_article" T4 ON ("foo_blog"."id" = T4."blog_id") 
WHERE ("foo_article"."creator_id" = 1  AND T4."creator_id" = 2 )

因此,虽然 WHERE 子句确实有 (A AND B),但 AB 引用了不同的内部联接("foo_article"."creator_id"T4."creator_id"),并且不是同一个表(这是 filter(A, B) 生成的表,(即: WHERE ("foo_article"."creator_id" = 1 and "foo_article"."creator_id" = 2))

(没有 distinct() 子句,如果您添加了任何一位作者的更多文章,您都会在查询集结果中获得多个 b2 条目。)

就像我说的,这是一个很棒的 ORM 练习!

This is a great question for exercising Django's ORM :-)

Depending on which parameters are known in advance, there are a couple ways to approach this.

Scenario 1: You know the users and the specific blog

If you have one particular blog in mind and want to simple find all articles written by either author, you can use a Q object. I don't think this is your scenario, but I'll put it here just in case:

from django.db.models import Q
Article.objects.filter(Q(creator=user1) | Q(creator=user2), blog=some_blog_instance)

Scenario 2: You know only the users

If you want to find all blogs where both users have published, and want to then find which articles they've published in those blogs, you'd want to start from the Blog model:

from django.db.models import Q

# Find all blogs where both user1 and user2 have written articles
blogs = Blog.objects.filter(article__creator=user1).\
        filter(article__creator=user2).distinct()

# Now find which articles those were
for blog in blogs:
    articles = blog.article_set.filter(Q=(creator=user1) | Q=(creator=user2))

Edit based on Paulo's comments:

Here is a test set of models that I believe matches the OP's pseudo code and which demonstrates the above code working (at least on sqlite3 and postgres):

from django.db import models
from django.contrib.auth.models import User

class Blog(models.Model):
    name = models.CharField(max_length=128)

class Article(models.Model):
    name = models.CharField(max_length=128)
    blog = models.ForeignKey(Blog)
    creator = models.ForeignKey(User)

Then some data where both user1 and user2 write articles on blog2:

u1 = User.objects.create(username='u1')
u2 = User.objects.create(username='u2')

b1 = Blog.objects.create(name='b1')
b2 = Blog.objects.create(name='b2')
b3 = Blog.objects.create(name='b3')

b1_art1 = Article.objects.create(name='b1_art1', blog=b1, creator=u1)
b2_art1 = Article.objects.create(name='b2_art1', blog=b2, creator=u1)
b2_art2 = Article.objects.create(name='b2_art2', blog=b2, creator=u2)

The query:

[b.name for b in Blog.objects.filter(article__creator=user1).\
    filter(article__creator=user2).distinct()]

produces:

[b2]

And the SQL is (my test django app was named foo):

SELECT "foo_blog"."id", "foo_blog"."name" 
FROM "foo_blog" 
INNER JOIN "foo_article" ON ("foo_blog"."id" = "foo_article"."blog_id") 
INNER JOIN "foo_article" T4 ON ("foo_blog"."id" = T4."blog_id") 
WHERE ("foo_article"."creator_id" = 1  AND T4."creator_id" = 2 )

So, while the WHERE clause does have (A AND B), A and B reference different inner joins ("foo_article"."creator_id" vs. T4."creator_id"), and not the same table (which is what filter(A, B) would generate, (ie: WHERE ("foo_article"."creator_id" = 1 and "foo_article"."creator_id" = 2))

(Without the distinct() clause, if you added more articles for either author, you'd get multiple b2 entries in the queryset results.)

Like I said, it's a great ORM exercise!

怎言笑 2024-10-17 02:46:04

我记得读过类似“Django ORM 85% 的情况下你能到达那里,另外 15% 的情况是 raw SQL" 在核心团队某人的演示中 - 但我再也找不到源代码了。

您的问题似乎适合 原始 SQL 的 15%< /a>.

I remember to read something like "Django ORM you get you there 85% of the time, the other 15% is raw SQL" in a presentation by someone from the core team - but I can't find the source anymore.

Your problem seems to fit that 15% of raw SQL.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文