【问题标题】:Django Postgres ArrayField aggregation and filteringDjango Postgres ArrayField 聚合和过滤
【发布时间】:2016-08-13 01:09:16
【问题描述】:

接着这个问题:Django Postgresql ArrayField aggregation

我有一个 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')

stacktrace 的底部是:

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?

【问题讨论】:

  • 可以使用docs.djangoproject.com/en/1.9/ref/models/querysets/#extra 来获取子查询。 annotate 似乎有点错误(通常用于聚合类型的函数)
  • 谢谢@Anentropic - 我确实看过extra,但看不到添加子查询的方法。下面的答案可能是“最真实的”——该模式真的不适合目的。我已经实现了一个迷你查询构建器,它从 ArrayFields 中进行选择和排序,并且看起来运行良好。
  • 我想知道您是否可以将子查询放在tables参数中

标签: django postgresql django-contrib


【解决方案1】:

您可能有错误的数据库设计。

提示:数组不是集合;搜索特定的数组元素可以 数据库设计错误的标志。考虑使用一个单独的表 将成为数组元素的每个项目的行。这会更容易 进行搜索,并且可能会更好地扩展大量 元素。

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

【讨论】:

  • 是的,我完全同意该设计不是最优的。但这不是我的设计,我现在坚持下去:(可怜的Animals!
  • 在这种情况下,没有理由不使用原始查询。原始查询并不邪恶。
  • 谢谢 - 我会试试看!
猜你喜欢
  • 2015-12-21
  • 2018-04-18
  • 1970-01-01
  • 2011-08-19
  • 2014-12-17
  • 2017-03-09
  • 1970-01-01
  • 2020-04-06
  • 2012-07-24
相关资源
最近更新 更多