Django / PostgreSQL varchar到UUID

时间:2016-02-01 20:36:12

标签: python sql django postgresql varchar

我试图将项目从Django 1.7更新到1.9。不幸的是,它使用了内部使用UUIDfield的django-extensions varchar。我试图将这些字段更改为数据库中的uuid类型。

我已经创建了一个自定义迁移,告诉Django迁移将使用自己的SQL来完成它。当我这样做时,我的问题出现了(列名为guid):

alter table tablename alter column guid type uuid using guid::uuid;

我收到此错误:

  

错误:运算符类" varchar_pattern_ops"不接受数据类型uuid

我对PostgreSQL并不熟悉,而且有点过头了。我可以创建一个CAST或其他东西来解决这个问题吗?我无法理解我的意思。

我正在尝试使用应该处理索引依赖关系的script from here,但我真的很想过。

3 个答案:

答案 0 :(得分:3)

DDL语句中的

type uuidSET DATA TYPE uuid的简写。 The manual:

  

SET DATA TYPE

     

此表单更改表的列类型。涉及该列的索引和简单表约束将通过重新分析最初提供的表达式自动转换为使用新列类型。 [...]

varchar_pattern_opsoperator class,如果您在任何索引中uuid使用此运算符类,则会在错误消息中提及该PostgreSQL LIKE query performance variations。通常用于实现更快的排序,模式匹配和范围条件。

修复,删除冲突的索引,更改数据类型,然后在没有特殊操作符类的情况下重新创建索引 - 如果仍然需要它们。

但是,一些使用varchar_pattern_ops索引的典型查询将停止使用数据类型uuid而不是varchar。像模式匹配:

确保修复任何此类查询。

Postgresql operator class "varchar_pattern_ops" does not accept data type integer一个相关的答案:

我建议略有不同的路线。删除索引,更改数据类型以及然后创建新索引会更便宜 - 如果它仍然有用。

DROP INDEX tbl_guid_varchar_pattern_ops_idx;

ALTER TABLE tbl ALTER COLUMN guid TYPE uuid USING guid::uuid;

CREATE INDEX tbl_guid_idx ON tbl (guid);

如何查找违规索引?

  

我需要弄清楚如何检查现有的指数。

在Postgres的现代版本中,您可以在psql中使用\d tbl获取表的现有索引。

获取给定表的所有完整CREATE INDEX语句:

SELECT pg_get_indexdef(indexrelid) || ';' AS idx
FROM   pg_index
WHERE  indrelid = 'public.tbl'::regclass;  -- optionally schema-qualified

只使用varchar_pattern_ops

SELECT pg_get_indexdef(i.indexrelid) || ';' AS idx
FROM   pg_index i
JOIN   pg_opclass o ON o.oid = ANY (i.indclass)
WHERE  i.indrelid = 'public.big'::regclass
AND    o.opcname = 'varchar_pattern_ops';

详细说明:

答案 1 :(得分:0)

我刚遇到此问题,想要添加信息。在解决问题时,我通过迁移包裹了我的头。任何可以添加到此的人,请随意,包括更正。

这个应用程序正在使用Django 1.11,Py3,并且正在SQLite上从早期本地开发人员迁移(仅仅是为了概念验证)。迁移到PG时,我遇到了同样的错误:

  

错误:运算符类“varchar_pattern_ops”不接受数据类型uuid

我能够通过两种方式解决它。在我的应用程序的早期阶段,我能够擦除并从头开始。我知道这很少是一个选项,但我的行为提供了有用的线索,可以在迁移或升级方案中解决此问题。当ORM使用不常见的时候,我有很好的SQL / PG排序。对我来说这个问题真的让人头疼。

问题

在我5岁的大脑中,问题来自于改变列类型,从字符串ish到UUID“native”。通过我的应用程序中的迁移,似乎创建了一个非UUID原生的列。随着Django模型UUIDField的引入,无法满足需求并抛出上述错误。这个问题类似于在DB中使用非int值从str转换为int类型。

修复信息

我能够解决这两种方式。

首先是通过Django的壁球迁移。我已经在我的应用程序中遇到了与UUID使用相关的类似错误,因此我意识到这种错误模式。通过压缩迁移,您可以跳过先前的非UUIDField列创建,并仅执行正确的列声明。当我重新跑步时(新鲜)migrate一切都很顺利。

第二种方式几乎不是变种,但我杀死了所有迁移并从当前状态开始。与前一个相同。

所以..

所有这一切都说,对我来说,我能够以一种在我脑海中起作用的方式对问题进行逆向工程。 “修复”是永远不会创建除UUIDField友好方式之外的列。我的问题与SQLite到PG交换(AFIK)有关。

如果我正在进行升级,我认为杀死索引和重新创建它们的解决方案是可行的方法。

再次,只是试图在这个错误上添加一些信息,googleweb没有返回任何真正抓住我的东西。所以我拿出了镐和闪光灯。

答案 2 :(得分:0)

从Postgresql 9.5开始,可能还有其他选项。现在有一个uuid运算符类https://www.postgresql.org/docs/9.5/static/brin-builtin-opclasses.html。当然,我仍然有9.4 :-(。这篇博文有助于解释问题并且有一个我认为仍然有效的修复,但它也是9.5之前的版本:https://coderwall.com/p/1b5eyq/index-for-uuid-array-data-type

请注意,博客专门引用了数组中uuid的使用,而新的运算符类专门引用了BRIN。警告Emptor。