PostgreSQL 字段中的 Django ProgrammingError

Django ProgrammingError in Fields on PostgreSQL

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。但是,这也引发了同样的错误。


环境

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

  1. JSONField 更改为 TextField

  2. 刷新你的数据库。

    Beware! This operation will erase all the data but the structure in your database.

  3. 删除所有应用程序中的所有 migrations 文件夹。

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

  5. 运行 python manage.py makemigrations <appname> && python3 manage.py migrate <appname> 对于您拥有的每个应用程序。

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

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

! This answer will be accepted as default if there will not occur any other better solution in 48 hours.

根据 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 来升级您的版本。

根据匿名评论,我发现以下方法有效:

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)
...

如果您收到此错误并且您安装了 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。如果不是,您可能安装了几个版本并且您的服务配置指向另一个版本。

对于旧版本的 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"