Django 不使用 Postgres
Posted
技术标签:
【中文标题】Django 不使用 Postgres【英文标题】:Django distinct not working with Postgres 【发布时间】:2016-08-09 19:15:33 【问题描述】:我正在配置一个 API 以提取结果列表。这些项目是服装“产品”,有几个“变体”。
我正在尝试使用 distinct 来确保查询集仅返回唯一产品列表 - 而不是由于许多变化而重复多次的同一产品。
过去,我在产品的主键 (id) 上使用了 distinct。但是,下面的代码不起作用。
我在尝试使用“distinct”时收到 500 错误。没有它-我没有错误。我不能在本地测试,因为 SQLite 不喜欢不同的。我正在使用
class InternalListView(APIView):
renderer_classes = (JSONRenderer, )
def get(self, request, *args, **kwargs):
filters =
for key, value in request.GET.items():
key = key.lower()
if key in countmatch:
lookup, val = internalmatch[key](value.lower())
filters[lookup] = val
qset = (
Product.objects
.filter(**filters)
.distinct('id')
.order_by('-rating')
.values('name', 'brand', 'rating')
.annotate(
price=F('variation__price__price'),
id=F('pk'),
vari=F('variation'),
)
)
for i in qset:
i['likes'] = random.randint(500, 1000)
print qset
return Response(qset.all())
【问题讨论】:
尝试获取 500 错误背后的错误消息,并尽可能发布异常的完整堆栈跟踪。但我的猜测是,错误消息是“SELECT DISTINCT ON 表达式必须匹配初始 ORDER BY 表达式”。带有字段名称的distinct()
是PostgreSQL 扩展,仅当distinct()
给出的字段也提供给第一个order_by()
时才有效。
一般来说,我真的建议安装一个本地 Postgres 服务器来尝试解决此类问题,这并不难。
【参考方案1】:
啊,刚刚想通了。
根据 django 文档 (https://docs.djangoproject.com/en/1.9/ref/models/querysets/#distinct)
distinct 和 order_by 必须相同。
所以这不起作用:
.distinct('id')
.order_by('-rating')
但这会起作用:
.distinct('id')
.order_by('id')
这是最好的:
.distinct('rating', 'id')
.order_by('-rating')
使用选项 3 有什么问题吗?
【讨论】:
distinct('id')
转换为SELECT DISTINCT ON
,即PostgreSQL extension。由于distinct()
消除了行,PostgreSQL 要求您指定定义的顺序,否则它将消除随机行,从而导致(可能)不可重复的选择。
这是一个限制,但它必须是不同列的 subset
并且不相同(如果是这样,那就是 django 而不是 pgsql)。 distinct
只会输出您要求的列,因此无法订购其他任何内容。
@AndrewBacker 有趣的是,PostgreSQL (9.4.6) 只有在 order_by 包含至少一列不在不同列表中时才会发出嘶嘶声。即SELECT DISTINCT ON (a, b) a, b, c ... ORDER BY a
有效。 SELECT DISTINCT ON (a, b) a, b, c ... ORDER BY a, c
失败,而 SELECT DISTINCT ON (a, b) a, b, c ... ORDER BY a, b, c
。被接受。不过,第一个被接受,在我看来是错误的。您会在输出中获得所有三列,但在第一种情况下,第一行可能是随机的。
@Ycon 选项 3 在语义上与其他两个不同。 distinct('id')
将消除所有具有相同 id 的行。 distinct('id', 'rating')
仅删除具有相同 id
AND rating
的重复行。
@dhke 有趣...我没有手动完成 lot 的 psql,但实际上我喜欢这种方式。这是 TSQL 中的一个 hack。我明白为什么#3 可能有效,但它只是事后合理化。也许它已经被 a & b 订购了,所以我们现在可以做 c.. 但如果 b 不存在,它就会混淆。以上是关于Django 不使用 Postgres的主要内容,如果未能解决你的问题,请参考以下文章
与 django-dynamic-formset 一起使用的 Django Formset 不显示删除链接
在不使用 Django 本身的情况下测试自定义 Django 中间件