Подтвердить что ты не робот

Как настроить django-hstore с помощью существующего приложения, управляемого югом?

Я попытался использовать django-hstore, используя этот хороший учебник. Я добавил два класса в существующее приложение, управляемое югом:

class Attribute(models.Model):
    name  = models.CharField(max_length=200, verbose_name=_("name"))
    description = models.CharField(max_length=1000, verbose_name=_("description"))

class Measure(models.Model):
    attribute = models.ForeignKey(Attribute)
    data = hstore.DictionaryField(db_index=True)
    objects = hstore.HStoreManager()

сделал a schemamigration --auto, запустил миграцию и получил django.db.utils.DatabaseError: type "hstore" does not exist.

Ладно, бабушка оказалась неполной, документация django-hstore сообщила мне, что я использую бэкэнд собственной базы данных, я добавил в свой файл настроек следующее:

DATABASES['default']['ENGINE'] = 'django_hstore.postgresql_psycopg2'

Тогда я получил KeyError: 'default' в south/db/__init__.py", line 78. На этом этапе intertubes + некоторые пробные/ошибки указали мне на переменную параметров SOUTH_DATABASE_ADAPTERS, и я добавил следующие настройки:

SOUTH_DATABASE_ADAPTERS = {'default': 'south.db.postgresql_psycopg2'}

Новая ошибка:

File ".../psycopg2/extras.py", line 769, in register_hstore
"hstore type not found in the database. "
psycopg2.ProgrammingError: hstore type not found in the database. please install it from your 'contrib/hstore.sql' file

Теперь это странно, потому что я установил расширение hstore:

$ sudo -u postgres psql
create extension hstore;
postgres=# CREATE EXTENSION hstore;
ERROR:  extension "hstore" already exists
postgres=# \dx
                           List of installed extensions
  Name   | Version |   Schema   |                   Description                    
---------+---------+------------+--------------------------------------------------
 hstore  | 1.0     | public     | data type for storing sets of (key, value) pairs
 plpgsql | 1.0     | pg_catalog | PL/pgSQL procedural language
(2 rows)
postgres=# SELECT 'hstore'::regtype::oid;
  oid  
-------
 57704
(1 row)

Как это должно работать? Я использую Django 1.4, Postgresql 9.1.

4b9b3361

Ответ 1

В итоге я обнаружил, что расширение hstore не было установлено для конкретной базы данных, которую я использовал:

$ psql -d mydb
psql (9.1.4)
Type "help" for help.

mydb=# SELECT t.oid, typarray FROM pg_type t JOIN pg_namespace ns ON typnamespace = ns.oid WHERE typname = 'hstore';
 oid | typarray 
-----+----------
(0 rows)

mydb=# \dx
                 List of installed extensions
  Name   | Version |   Schema   |         Description          
---------+---------+------------+------------------------------
 plpgsql | 1.0     | pg_catalog | PL/pgSQL procedural language
(1 row)

mydb=# create extension hstore;
WARNING:  => is deprecated as an operator name
DETAIL:  This name may be disallowed altogether in future versions of PostgreSQL.
CREATE EXTENSION
mydb=# \dx
                           List of installed extensions
  Name   | Version |   Schema   |                   Description                    
---------+---------+------------+--------------------------------------------------
 hstore  | 1.0     | public     | data type for storing sets of (key, value) pairs
 plpgsql | 1.0     | pg_catalog | PL/pgSQL procedural language
(2 rows)

mydb=# SELECT t.oid, typarray FROM pg_type t JOIN pg_namespace ns ON typnamespace = ns.oid WHERE typname = 'hstore';
  oid  | typarray 
-------+----------
 58800 |    58805
(1 row)

Я думал, что база данных, созданная после установки hstore, будет включать расширение. Кажется, не так, Я неправильно истолковал, как работают расширения? Являются ли они специфичными для базы данных?

Ответ 2

Со времени моего последнего ответа Django устарел и удалил сигнал pre_syncdb. Я обновил ответ, чтобы разместить более свежие версии. Основная механика идентична для более новых версий, поскольку оба метода полагаются на сигналы и код SQL, который выполняется только в том случае, если расширение HSTORE не существует.

Django 1.8 +

Поскольку Django вводил миграции DB, сигналы pre_syncdb были отмечены устаревшими в 1.7 и полностью удалено в 1.9. Однако они ввели новый сигнал под названием pre_migrate, который можно использовать таким же образом.

Пример:

"""
This is an example models.py which contains all model definition.
"""
from django.db import connection, models
from django.db.models.signals import pre_migrate
from django.dispatch import receiver
import sys

# sender is optional but will be called for every pre_migrate signal if removed
@receiver(pre_migrate, sender=sys.modules[__name__])
def setup_postgres_hstore(sender, **kwargs):
    """
    Always create PostgreSQL HSTORE extension if it doesn't already exist
    on the database before syncing the database.
    Requires PostgreSQL 9.1 or newer.
    """
    cursor = connection.cursor()
    cursor.execute("CREATE EXTENSION IF NOT EXISTS hstore")

# ...rest of your model definition goes here
class Foo(models.Model):
    # ...field definitions, etc.

Django 1.6+ (исходный ответ)

Один из способов гарантировать, что расширение HSTORE будет установлено во время ./manage.py syncdb, - это использовать pre_syncdb сигналы в вашем файле models.py, который был введен с Django 1.6.

Пример:

"""
This is an example models.py which contains all model definition.
"""
from django.db import connection, models
from django.db.models.signals import pre_syncdb
from django.dispatch import receiver
import sys

# sender is optional but will be called for every pre_syncdb signal if removed
@receiver(pre_syncdb, sender=sys.modules[__name__])
def setup_postgres_hstore(sender, **kwargs):
    """
    Always create PostgreSQL HSTORE extension if it doesn't already exist
    on the database before syncing the database.
    Requires PostgreSQL 9.1 or newer.
    """
    cursor = connection.cursor()
    cursor.execute("CREATE EXTENSION IF NOT EXISTS hstore")

# ...rest of your model definition goes here
class Foo(models.Model):
    # ...field definitions, etc.

Я считаю, что это полезно, если вы не хотите запускать его для каждого нового экземпляра базы данных. Этот метод также работает для модульных тестов Django во время установки тестовой базы данных.

Дополнительная информация о сигнальных крючках в Django: https://docs.djangoproject.com/en/1.6/ref/signals/#management-signals