2016-04-20 127 views
0

從這個問題繼:Django Postgresql ArrayField aggregationDjango的Postgres的ArrayField聚合和過濾

我有分類的ArrayField,我想找回它擁有所有的獨特的價值觀 - 但是結果應進行篩選,以便只值與開始提供的字符串被返回。

什麼是「最Django」的做法?

給定一個Animal模型,看起來像這樣:

class Animal(models.Model): 
    # ... 
    categories = ArrayField(
     models.CharField(max_length=255, blank=True), 
     default=list, 
    ) 
    # ... 

然後,按照the other question's answer,這適用於尋找所有類別,過濾。

all_categories = (
    Animal.objects 
    .annotate(categories_element=Func(F('categories'), function='unnest')) 
    .values_list('categories_element', flat=True) 
    .distinct() 
) 

不過,現在,當我嘗試過濾結果我得到的失敗,不僅僅是__startswith但所有類型的filter

all_categories.filter(categories_element__startswith('ga')) 
all_categories.filter(categories_element='dog') 

堆棧跟蹤的底部是:

DataError: malformed array literal: "dog" 
... 
DETAIL: Array value must start with "{" or dimension information. 

...看起來,這是因爲Django試圖做第二個UNNEST - 這是它產生的SQL:

...) WHERE unnest("animal"."categories") = dog::text[] 

如果我寫在PSQL查詢則似乎需要一個子查詢爲UNNEST的結果:

SELECT categories_element 
FROM (
    SELECT UNNEST(animal.categories) as categories_element 
) ul 
WHERE ul.categories_element like 'Ga%'; 

有沒有辦法讓Django的ORM,使工作查詢?或者我應該放棄ORM並使用原始SQL?

+0

也許可以使用https://docs.djangoproject.com/en/1.9/ref/models/querysets/#extra得到子查詢在那裏。 'annotate'似乎有些錯誤(通常用於聚合類型函數) – Anentropic

+0

Thanks @Antropic - 我確實看過'extra',但看不到添加子查詢的方法。下面的答案可能是「最真實」的 - 模式並不適合真正的目的。我已經實現了一個迷你查詢構建器,可以從ArrayFields中進行選擇和排序,並且看起來很好地工作。 – jamesc

+0

我想知道你是否可以把子查詢放在'tables'參數中 – Anentropic

回答

1

您可能有錯誤的數據庫設計。

提示:數組不是集;搜索特定數組元素可能是數據庫錯誤設計的標誌。考慮使用一個帶有 行的單獨表格作爲數組元素。這將更容易 進行搜索,並且可能對大量元素進行更好的縮放。

http://www.postgresql.org/docs/9.1/static/arrays.html

+0

是的,我完全同意這個設計不是最優的。但這不是我的設計,現在我堅持使用它:(Poor'Animal's! – jamesc

+0

在這種情況下,沒有理由不使用原始查詢。原始查詢不是邪惡的。 – e4c5

+0

謝謝 - 我會放手一搏! – jamesc