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 字段的定义不正确,因为它指定它是 CharFields 的数组,但实际上它是枚举数组。 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:列“日期”不存在

ProgrammingError:列“product”的类型是product[],但表达式的类型是text[] enum postgres

pymysql.err.programmingError: (1064)

ProgrammingError:关系 django_session 的权限被拒绝

SQLAlchemy(psycopg2.ProgrammingError)无法适应类型'dict'

psycopg2.ProgrammingError:“st”或附近的语法错误\r,