2016-04-20 125 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