django model filter_Django分表的两个方案
由來
知乎上的一個問題:Django 分表 怎么實現(xiàn)?
這個問題戳到了Django ORM的痛點,對于多數(shù)據(jù)庫/分庫的問題,Django提供了很好的支持,通過using和db router可以很好的完成多數(shù)據(jù)庫的操作。但是說到分表的問題,就有點不那么友好了。但也不是那么難處理,只是處理起來不太優(yōu)雅。
解析
在Django中,數(shù)據(jù)庫訪問的邏輯基本上是在Queryset中完成的,一個查詢請求,比如:User.objects.filter(group_id=10)。
其中的objects其實就是models.Manager,而Manager又是對QuerySet的一個包裝。而QuerySet又是最終要轉(zhuǎn)換為sql的一個中間層(就是ORM種,把Model操作轉(zhuǎn)換為SQL語句的部分)。所以當(dāng)我們寫下User.objects的時候,就已經(jīng)確定了要訪問的是哪個表了,這是由class Meta中的db_table決定的。
class理論上講,我們可以通過在運行時修改db_table來完成分表CRUD的邏輯,但是the5fire在看了又看源碼之后,還是沒找到如何下手。還是上面的問題,當(dāng)執(zhí)行到User.objects的時候,表已經(jīng)確定了,當(dāng)執(zhí)行到User.objects.filter(group=10)的時候只不過是在已經(jīng)生成好的sql語句中增加了一個where部分語句。所以并沒有辦法在執(zhí)行filter的時候來動態(tài)設(shè)置db_table。
對于問題中說的get也是一樣,因為get本身就是在執(zhí)行完filter之后從_result_cache列表中獲取的數(shù)據(jù)(_result_cache[0])。
方案一
根據(jù)the5fire上面的分析,要想在執(zhí)行具體查詢時修改db_table已經(jīng)是不可能了(當(dāng)然,如果你打算去重寫Model中Meta部分的邏輯以及Queryset部分的邏輯,就當(dāng)我沒說,我只能表示佩服)。
所以只能從定義層面下手了。也就是我需要定義多個Model,同樣的字段,不同的db_table。大概是這樣。
class這樣在User.objects.get(id=3)的時候,如果按照模2計算,那就是User01.objects.get(id=3),笨點的方法就是寫一個dict:
user_sharding_map如果真的這么寫那Python作為動態(tài)語言,還有啥用,你分128張表試試。我們應(yīng)該動態(tài)創(chuàng)建出User01,User02,....UserN這樣的表。
class嗯,這樣看起來似乎好了一下,但是還有問題,id=3需要傳兩次,如果兩次不一致,那就麻煩了。Model層要為上層提供統(tǒng)一的入口才行。
class MyUser(models.Model):# 增加方法 BY the5fire@classmethoddef sharding_get(cls, id=None, **kwargs):assert id, 'id is required!'Model = cls.get_sharding_model(id=id)return Model.objects.get(id=id, **kwargs)對上層來書,只需要執(zhí)行MyUser.sharding_get(id=10)即可。不過這改變了之前的調(diào)用習(xí)慣 objects.get 。
不管怎么說吧,這也是個方案,更完美的方法就不繼續(xù)探究了,在Django的ORM中鉆來鉆去尋找可以hook的點實在憋屈。
我們來看方案二吧
方案二
ORM的過程是這樣的,Model——> SQL ——> Model,在方案一中我們一直在處理Model——> SQL的部分。其實我們可以拋開這一步,直接使用raw sql。
QuerySet提供了raw這樣的接口,用來讓你忽略第一層轉(zhuǎn)換,但是有可以使用從SQL到Model的轉(zhuǎn)換。只針對SELECT的案例:
class大概這么個意思吧,代碼可以再嚴(yán)謹(jǐn)些。
總結(jié)
單純看方案一的話,可能會覺得這么大量數(shù)據(jù)的項目,就別用Django了。其實the5fire第一次嘗試找一個優(yōu)雅的方式hack db_table時,也是一頭灰。但是,所有的項目都是由小到大的,隨著數(shù)據(jù)/業(yè)務(wù)的變大,技術(shù)人員應(yīng)該也會更加了解Django,等到一定階段之后,可能發(fā)現(xiàn),用其他更靈活的框架,跟直接定制Django成本差不多。
補(bǔ)充兩個github repo: - JBKahn/django-sharding - disqus/sharding-example
----EOF-----
掃碼關(guān)注,或者搜索微信公眾號:Python程序員雜談
總結(jié)
以上是生活随笔為你收集整理的django model filter_Django分表的两个方案的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: wxpython 安装_下载和安装wxP
- 下一篇: python读excel字体颜色_pyt