前天碰到了一個狀況,思考了很久沒能想出問題,昨天下午在 stackoverflow 上問了一下,有一個好心人跟我溝通了一下,瞭解清楚個人問題之後,到了晚上給出了答案,我操做了一下果真是正確的,讓我感動不已。他是一個好人,好人一輩子平安。數據庫
開始描述個人問題吧,標題不能描述清楚個人問題,我應該在正文詳細描述一下fetch
有 用戶( User ) 、發佈狀態( Feed ) 、評論( Comment ) 三個 Model,分別定義以下code
class User(models.Model): name = models.CharField(max_length=20) class Feed(models.Model): user = models.ForeignKey(User, related_name="feed_user") class Comment(models.Model): user = models.ForeignKey(User, related_name="comment_user") feed = models.ForeignKey(Feed, related_name="comment_feed")
數據庫目前的記錄對象
id | name |
---|---|
1 | Jack |
2 | Bruce |
id | user |
---|---|
1 | 1 |
id | user | feed |
---|---|---|
1 | 2 | 1 |
2 | 1 | 1 |
我須要獲取一個用戶的全部 Feed ,每個 Feed 包含它全部的 Comment ,可是每個 Comment 對應的 user 不能是 Feed 對應的 user 。ci
說白了我就是想獲取不是我本身的全部 Comment 。路由
我能想到的就是使用 exclude 、 Q 這些方法。因此一開始個人獲取方式以下:get
從上面的數據庫記錄來看, Jack 發了一條 Feed, 這條 Feed 有兩條 Comment,一條是 Bruce 評論的,還有一條是 Jack 本身評論的。博客
Feed.objects.filter(user=1)
序列化結果以下it
[ { "feed": { "id": 1, "user": { "id": 1 }, "comment": [ { "id": 1, "user": { "id": 2 }, "feed": { "id": 1, "user": { "id": 1 } } }, { "id": 2, "user": { "id": 1 }, "feed": { "id": 1, "user": { "id": 1 } } } ] } } ]
Feed.objects.filter(user=1).exclude(feed_user__user=1)
這種方法獲取的序列化結果table
[ { "feed": { "id": 1, "user": { "id": 1 }, "comment": [] } } ]
此時的序列化結果居然把整個 comment 過濾掉了
經過查看 queryset 的 SQL 語句
SELECT `feed_feed`.`id`, `feed_feed`.`user_id` FROM `feed_feed` WHERE NOT (`feed_feed`.`id` IN (SELECT U1.`feed_id_id` AS Col1 FROM `feed_comment` U1 WHERE U1.`user_id` = 1)) ORDER BY `feed_feed`.`create_time` DESC
發現它是經過判斷 Jack 是否出如今全部評論中的某一個, 所以若是出現了就認爲整個都不要了,這種方式不可取。
prefetch_related 返回一個 QuerySet ,爲每一個關係單獨查找,並在 Python 中「加入」。這容許它預取多對多和多對一對象,除了外鍵和一對一關係。
Feed.objects.filter(user=1).prefetch_related( Prefetch( "feed_comment", queryset=Comment.objects.exclude( user=1 ), to_attr="all_comment" ) )
此時的序列化結果以下
[ { "feed": { "id": 1, "user": { "id": 1 }, "comment": [ { "id": 1, "user": { "id": 2 }, "feed": { "id": 1, "user": { "id": 1 } } }, { "id": 2, "user": { "id": 1 }, "feed": { "id": 1, "user": { "id": 1 } } } ], "all_comment": [ { "id": 1, "user": { "id": 2 }, "feed": { "id": 1, "user": { "id": 1 } } } ] } } ]
結果在 Jack 全部的 Feed 基礎上,添加了一個 all_comment 字段,而這個字段正好是過濾了 Jack 的評論,是我要的最終結果。
原文地址:獲取一些包含多對多外鍵可是不包含特定另外一個外鍵的結果
個人博客:時空路由器