短intoduction的問題...如何避免在Django自定義數據庫函數調用周圍的SQL中括號?
- PostgreSQL有非常整齊地排列字段(int數組,字符串數組)和功能對他們來說就像
UNNEST
和ANY
。 - Django支持這些字段(我使用的是
djorm_pgarray
),但函數不是本機支持的。 - 可以使用
.extra()
,但Django 1.8引入了一個新概念database functions。
讓我提供一個最基本的例子,我基本上用這些做了什麼。 A Dealer
有一個它支持的make的列表。 A Vehicle
有一個品牌,並與經銷商聯繫在一起。但碰巧Vehicle
的製作與Dealer
的製作清單不符,這是不可避免的。
MAKE_CHOICES = [('honda', 'Honda'), ...]
class Dealer(models.Model):
make_list = TextArrayField(choices=MAKE_CHOICES)
class Vehicle(models.Model):
dealer = models.ForeignKey(Dealer, null=True, blank=True)
make = models.CharField(max_length=255, choices=MAKE_CHOICES, blank=True)
有經銷商數據庫,並讓,我要統計所有車輛,車輛的品牌和其經銷商的使列表做匹配。這就是我如何避免.extra()
。
from django.db.models import functions
class SelectUnnest(functions.Func):
function = 'SELECT UNNEST'
...
Vehicle.objects.filter(
make__in=SelectUnnest('dealer__make_list')
).count()
產生的SQL:
SELECT COUNT(*) AS "__count" FROM "myapp_vehicle"
INNER JOIN "myapp_dealer"
ON ("myapp_vehicle"."dealer_id" = "myapp_dealer"."id")
WHERE "myapp_vehicle"."make"
IN (SELECT UNNEST("myapp_dealer"."make_list"))
和它的作品,而且比我們能在Django使用傳統的M2M方法快得多。但是,對於這項任務,UNNEST
不是一個很好的解決方案:ANY
要快得多。我們來試試吧。
class Any(functions.Func):
function = 'ANY'
...
Vehicle.objects.filter(
make=Any('dealer__make_list')
).count()
生成下面的SQL:
SELECT COUNT(*) AS "__count" FROM "myapp_vehicle"
INNER JOIN "myapp_dealer"
ON ("myapp_vehicle"."dealer_id" = "myapp_dealer"."id")
WHERE "myapp_vehicle"."make" =
(ANY("myapp_dealer"."make_list"))
它失敗了,因爲周圍ANY
括號是假的。如果刪除它們,它將在psql
控制檯中順利運行,而且速度很快。
所以我的問題。
- 有沒有什麼辦法去除這些大括號?我在Django文檔中找不到任何關於此的信息。
- 如果沒有, - 也許還有其他方法來重述這個查詢?
P. S.我認爲,廣泛的用於不同的後端數據庫函數庫將是數據庫重的Django應用程序非常有用。
當然,其中大多數不會是便攜式的。但是,您通常不會經常將這樣的項目從一個數據庫後端遷移到另一個數據庫。在我們的例子中,使用數組字段和PostGIS我們堅持使用PostgreSQL,並且不打算移動。
有人開發這樣的東西嗎?
P. P. S.有人可能會說,在這種情況下,我們應該使用單獨的表來製作和intarray而不是字符串數組,這是正確的,並且會完成,但問題的性質不會改變。
UPDATE。
TextArrayField
在djorm_pgarray定義。在鏈接的源文件中,您可以看到它的工作原理。- 該值是文本字符串的列表。在Python中,它被表示爲一個列表。例如:
['honda', 'mazda', 'anything else']
。
下面是關於它在數據庫中的說法。
=# select id, make from appname_tablename limit 3;
id | make
---+----------------------
58 | {vw}
76 | {lexus,scion,toyota}
39 | {chevrolet}
而底層的PostgreSQL字段類型是text[]
。
這是最有趣的,我覺得雖然它沒有明確的文件中提到,FUNC鍵,它的子類可以只用於統計和標註但不在過濾器中。 – e4c5
我甚至嘗試覆蓋Func中的as_sql方法,看看是否可以用來去掉括號。但事實證明,括號被添加到其他地方 – e4c5
@ e4c5是的,我也查看了源代碼。也許有人深入Django ORM內部並且可以回答這個問題。 – Altaisoft