ProgrammingError:列“product”的类型是product[],但表达式的类型是text[] enum postgres
Posted
技术标签:
【中文标题】ProgrammingError:列“product”的类型是product[],但表达式的类型是text[] enum postgres【英文标题】:ProgrammingError: column "product" is of type product[] but expression is of type text[] enum postgres 【发布时间】:2017-07-22 19:19:41 【问题描述】:我想保存枚举数组。
我有以下:
CREATE TABLE public.campaign
(
id integer NOT NULL,
product product[]
)
产品是enum
。
在 Django 中我是这样定义的:
PRODUCT = (
('car', 'car'),
('truck', 'truck')
)
class Campaign(models.Model):
product = ArrayField(models.CharField(null=True, choices=PRODUCT))
但是,当我写以下内容时:
campaign = Campaign(id=5, product=["car", "truck"])
campaign.save()
我收到以下错误:
ProgrammingError: column "product" is of type product[] but expression is of type text[]
LINE 1: ..."product" = ARRAY['car...
注意 我看到了this 的回答,但我不使用sqlalchemy,如果不需要,我宁愿不使用它。
已编辑 我在下面尝试了@Roman Konoval 的建议:
class PRODUCT(Enum):
CAR = 'car'
TRUCK = 'truck'
class Campaign(models.Model):
product = ArrayField(EnumField(PRODUCT, max_length=10))
并与:
campaign = Campaign(id=5, product=[CAR, TRUCK])
campaign.save()
但是,我仍然遇到同样的错误,
我看到 django 正在将其转换为字符串列表。 如果我直接在 psql 控制台中编写以下内容:
INSERT INTO campaign ("product") VALUES ('car,truck'::product[])
效果很好
【问题讨论】:
如何在 postgresql 中定义产品 - 作为 CREATE TYPE、TABLE? 我把它定义为 enu 【参考方案1】:这里有两个基本问题。
不要使用枚举
如果您继续使用枚举,您在 *** 上的下一个问题将是“如何向枚举添加新条目?”。 Django 不支持开箱即用的枚举类型(感谢上帝)。所以你必须为此使用第三方库。您的里程会因图书馆的完善程度而异。
一个枚举值在磁盘上占用四个字节。枚举的长度 值的文本标签受编译的 NAMEDATALEN 设置的限制 进入PostgreSQL;在标准版本中,这意味着最多 63 个字节。
如果您认为通过使用枚举来节省磁盘空间,manual 的上述引用表明这是一种错觉。
查看Q&A 了解更多关于枚举的优缺点。但总的来说,弊大于利。
不要使用数组
提示:数组不是集合;搜索特定的数组元素可以 数据库设计错误的标志。考虑使用一个单独的表 将成为数组元素的每个项目的行。这会更容易 进行搜索,并且可能会更好地扩展大量 元素。
来源:https://www.postgresql.org/docs/9.6/static/arrays.html
如果您要搜索与汽车或卡车有关的广告系列,您将不得不做很多艰苦的工作。数据库也是如此。
正确的设计
正确的设计是 postgresql 数组文档页面中建议的设计。创建相关表。这也是标准的 django 方式。
class Campaign(models.Model):
name = models.CharField(max_length=20)
class Product(Models.model):
name = models.CharField(max_length=20)
campaign = models.ForeignKey(Campaign)
这使您的代码更简单。不需要任何额外的存储空间。不需要第三方库。最棒的是,django related models 的大量 API 可供您使用。
【讨论】:
我认为 postgres 只为枚举的值保存一个 1 位作为索引 - 不是吗? 否则手册会保存。即便如此,您也至少需要拥有大约 500 万条记录才能节省大量资金。根本不值得。 在选择使用 postgres 枚举时,还有一些其他可能相关的事情:1) 对文本进行排序是区域设置感知的,因此它比对整数排序慢很多(因为枚举被压制为) ,这是普遍存在的,因为所有索引都根据语言环境进行排序。 2)如果您实际上为非字典的枚举值指定了排序顺序,则很难实现 @edruid 比如? ... 如果只是文本,按名称排序不是很有用。当然,当这样一个假设项目的工作流程发生变化时,枚举需要 DDL 语句来调整它。这通常需要在应用程序中进行迁移。但是,如果它是一个联结表,它没有可用的 UI 修改,那么该应用程序仍然需要迁移、插入新行、删除不推荐使用的行等。我承认,这个用例非常小,但它存在。 【参考方案2】:product
字段的定义不正确,因为它指定它是 CharField
s 的数组,但实际上它是枚举数组。 Django does not 现在支持枚举类型,所以你可以尝试this extension 正确定义类型:
class Product(Enum):
ProductA = 'a'
...
class Campaign(models.Model):
product = ArrayField(EnumField(Product, max_length=<whatever>))
【讨论】:
谢谢,但没有帮助。请参阅我更新的问题。非常感谢! 如果我尝试单个枚举,它可以工作。但不适用于 ArrayField。 如果我直接写:INSERT INTO campaign ("product") VALUES ('car,truck'::product[]) 它工作得很好【参考方案3】:试试这个:
def django2psql(s):
return ''+','.join(s) + ''
campaign = Campaign(id=5, product=django2psql(["car", "truck"]))
【讨论】:
【参考方案4】:我认为您可能必须继承 CharField
才能让它报告正确的 db_type
。可能还有比这更多的问题,但您可以尝试一下:
class Product(models.CharField):
def db_type(self, connection):
return 'product'
PRODUCT = (
('car', 'car'),
('truck', 'truck')
)
class Campaign(models.Model):
product = ArrayField(Product(null=True, choices=PRODUCT))
【讨论】:
我还没有实际测试过上面的代码,但是阅读它看起来应该可以工作的代码......以上是关于ProgrammingError:列“product”的类型是product[],但表达式的类型是text[] enum postgres的主要内容,如果未能解决你的问题,请参考以下文章
ProgrammingError:列“product”的类型是product[],但表达式的类型是text[] enum postgres
pymysql.err.programmingError: (1064)
ProgrammingError:关系 django_session 的权限被拒绝