PostgreSQL 字段中的 Django ProgrammingError

Posted

技术标签:

【中文标题】PostgreSQL 字段中的 Django ProgrammingError【英文标题】:Django ProgrammingError in Fields on PostgreSQL 【发布时间】:2016-10-12 21:12:13 【问题描述】:

models.py

​​>
class Stop(models.Model):
    idn = models.PositiveIntegerField(primary_key=True, unique=True)
    label = models.CharField(null=False, blank=False, max_length=512)
    coor_x = models.FloatField()
    coor_y = models.FloatField()
    buses = models.ManyToManyField(Bus)
    latest_query_datetime = models.DateTimeField(default=datetime(2000, 1, 1, 0, 0, 0))
    latest_query_data = JSONField(default=)

    class Meta:
    ordering = ["label"]

    def __str__(self):
    return self.label

当我跑步时:

python3 manage.py makemigrations && python3 manage.py migrate

它引发ProgrammingError 表示 jsonb 数据类型不存在:

Migrations for 'rest':
  0007_auto_20160612_1301.py:
    - Alter field latest_query_data on stop
Operations to perform:
  Apply all migrations: contenttypes, rest, auth, sessions, admin
Running migrations:
  Rendering model states... DONE
  Applying rest.0005_auto_20160612_1237...Traceback (most recent call last):
  File "/home/erayerdin/.venv/eshot-api/lib/python3.5/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
psycopg2.ProgrammingError: type "jsonb" does not exist
LINE 1: ... TABLE "rest_stop" ADD COLUMN "latest_query_data" jsonb DEFA...
                                                         ^


The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/home/erayerdin/.venv/eshot-api/lib/python3.5/site-packages/django/core/management/__init__.py", line 353, in execute_from_command_line
    utility.execute()
  File "/home/erayerdin/.venv/eshot-api/lib/python3.5/site-packages/django/core/management/__init__.py", line 345, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/erayerdin/.venv/eshot-api/lib/python3.5/site-packages/django/core/management/base.py", line 348, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/home/erayerdin/.venv/eshot-api/lib/python3.5/site-packages/django/core/management/base.py", line 399, in execute
    output = self.handle(*args, **options)
  File "/home/erayerdin/.venv/eshot-api/lib/python3.5/site-packages/django/core/management/commands/migrate.py", line 200, in handle
    executor.migrate(targets, plan, fake=fake, fake_initial=fake_initial)
  File "/home/erayerdin/.venv/eshot-api/lib/python3.5/site-packages/django/db/migrations/executor.py", line 92, in migrate
    self._migrate_all_forwards(plan, full_plan, fake=fake, fake_initial=fake_initial)
  File "/home/erayerdin/.venv/eshot-api/lib/python3.5/site-packages/django/db/migrations/executor.py", line 121, in _migrate_all_forwards
    state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
  File "/home/erayerdin/.venv/eshot-api/lib/python3.5/site-packages/django/db/migrations/executor.py", line 198, in apply_migration
    state = migration.apply(state, schema_editor)
  File "/home/erayerdin/.venv/eshot-api/lib/python3.5/site-packages/django/db/migrations/migration.py", line 123, in apply
    operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
  File "/home/erayerdin/.venv/eshot-api/lib/python3.5/site-packages/django/db/migrations/operations/fields.py", line 62, in database_forwards
    field,
  File "/home/erayerdin/.venv/eshot-api/lib/python3.5/site-packages/django/db/backends/base/schema.py", line 396, in add_field
    self.execute(sql, params)
  File "/home/erayerdin/.venv/eshot-api/lib/python3.5/site-packages/django/db/backends/base/schema.py", line 110, in execute
    cursor.execute(sql, params)
  File "/home/erayerdin/.venv/eshot-api/lib/python3.5/site-packages/django/db/backends/utils.py", line 79, in execute
    return super(CursorDebugWrapper, self).execute(sql, params)
  File "/home/erayerdin/.venv/eshot-api/lib/python3.5/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
  File "/home/erayerdin/.venv/eshot-api/lib/python3.5/site-packages/django/db/utils.py", line 95, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "/home/erayerdin/.venv/eshot-api/lib/python3.5/site-packages/django/utils/six.py", line 685, in reraise
    raise value.with_traceback(tb)
  File "/home/erayerdin/.venv/eshot-api/lib/python3.5/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: type "jsonb" does not exist
LINE 1: ... TABLE "rest_stop" ADD COLUMN "latest_query_data" jsonb DEFA...

我使用 PostgreSQL 来使用 JSONField 并在用户请求视图时对其进行更新。如果我不使用default=,它会告诉我制作一个。

进一步分析

我将latest_query_data 字段更改为TextField,以便我可以存储为字符串并在需要时转换为dict。但是,这也引发了同样的错误。


环境

django 1.9.6 psycopg 2.6.1

【问题讨论】:

也许这个答案对于 psycopg 2.6 仍然适用? ***.com/questions/25263736/… 嗯,我尝试了几种方法,添加myproject/__init__.pymyproject/settings.pymyapp/models.py。它仍然引发同样的错误,奇怪。 【参考方案1】:

根据 Django 文档,JSONField 需要 PostgreSQL ≥ 9.4 和 Psycopg2 ≥ 2.5.4

您使用的是哪个 PostgreSQL 版本?

见https://docs.djangoproject.com/en/dev/ref/contrib/postgres/fields/#django.contrib.postgres.fields.JSONField

Ubuntu 14.04 存储库仅包含 9.3 版本。您可以查看this 以升级您的版本。

【讨论】:

上面写着 9.3.13。如果可行,我会尝试并接受。 对于那些不能升级postgres的人,你可以改为扩展JSONField并覆盖db_type方法返回json(而不是jsonb)。 Postgres 在 9.2 中引入了 json 数据类型,从 django 的角度来看没有区别。对我来说很好。【参考方案2】:

根据匿名评论,我发现以下方法可行:

from django.contrib.postgres import fields

class OldJSONField(fields.JSONField):
    def db_type(self, connection):
        return 'json'

class Stop(models.Model):
    ...
    latest_query_data = OldJSONField(default=dict)
...

【讨论】:

使用 作为默认值使其成为所有实例之间共享的可变值,请改用default=dict。来自文档:docs.djangoproject.com/en/2.2/ref/contrib/postgres/fields/…【参考方案3】:

如果您收到此错误并且您安装了 Postgres > 9.4,那么我会检查您是否连接到也安装在您的实例上的旧版 Postgres。

要确认您从 Django 连接的内容,您可以在 shell 中使用 psycopg2

import psycopg2
conn = psycopg2.connect("dbname=<your database> user=<your user> password=<your password>")
cur = conn.cursor()
cur.execute("SELECT Version();")
cur.fetchone()

确保此处的版本 > 9.4。如果没有,您可能安装了几个版本,并且您的服务配置指向另一个版本。

【讨论】:

【参考方案4】:

对于旧版本的 PostgreSQL,例如“PostgreSQL9.2.x”,

我们可以使用替代方法

from jsonfield import JSONField

代替:

from django.contrib.postgres.fields import JSONField

例如:

from django.db import models
from jsonfield import JSONField

class MyModel(models.Model):
      json = JSONField()

可以安装为:

 pip install jsonfield

检查一下: Add support for PostgreSQL 9.2+'s native json type. #32

此解决方案特别适用于某些限量版。例如, 在默认支持 postgresql9.2 的 VPS & Cpanel 上

更多详情!see"rpkilby-jsonfield"

【讨论】:

【参考方案5】:

所以,这似乎是 psycopg2 或 django 上的一个错误,我将在两个存储库上发布一个问题。这就是我解决问题的方法(至少,ProgrammingError)。

    JSONField 更改为TextField

    刷新您的数据库。

    小心!此操作将清除数据库中除结构之外的所有数据。

    删除所有应用中的所有 migrations 文件夹。

    在您的所有应用中运行 python3 manage.py makemigrations &amp;&amp; python3 manage.py migrate

    为您拥有的每个应用运行python manage.py makemigrations &lt;appname&gt; &amp;&amp; python3 manage.py migrate &lt;appname&gt;

    使用内置的json模块在strdict之间进行转换。

但是,请记住,如果您要过滤模型的 QuerySet,此解决方案需要付出很多努力。我不推荐它,但没有其他解决方案可以摆脱这个错误,我需要做的就是保存数据并表示它。

如果在 48 小时内没有其他更好的解决方案,此答案将被默认接受。

【讨论】:

以上是关于PostgreSQL 字段中的 Django ProgrammingError的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Django ORM 中映射 PostgreSQL 数组字段

尝试在 Django 中使用外键列表创建 PostgreSQL 字段

django postgresql json 字段模式验证

每行中有太多空字段会影响 PostgreSQL 中的搜索性能吗?

PostgreSQL 9.4:在数组内的 JSON 字段 id 上聚合/连接表

Django/PostgreSQL varchar 到 UUID