python - postgres - ¿Cómo configurar django-hstore con una aplicación existente administrada por south?
django y postgresql (3)
Intenté usar django-hstore usando este bonito tutorial . Agregué dos clases a una aplicación existente administrada por South:
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()
realizó un schemamigration --auto
, lanzó la migración y obtuvo un django.db.utils.DatabaseError: type "hstore" does not exist
.
De acuerdo, el tuto parecía estar incompleto, la documentation django-hstore me dijo que usara la base de datos personalizada, agregué lo siguiente a mi archivo de configuración:
DATABASES[''default''][''ENGINE''] = ''django_hstore.postgresql_psycopg2''
Luego obtuve un KeyError: ''default''
en south/db/__init__.py", line 78
En este punto, los intertubes + algunos ensayos / errores me SOUTH_DATABASE_ADAPTERS
variable de configuración SOUTH_DATABASE_ADAPTERS
y SOUTH_DATABASE_ADAPTERS
lo siguiente a la configuración:
SOUTH_DATABASE_ADAPTERS = {''default'': ''south.db.postgresql_psycopg2''}
Nuevo error:
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
Ahora esto es extraño porque instalé la extensión 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)
Cómo se supone que esto funcione ? Estoy usando Django 1.4, Postgresql 9.1.
Desde mi última respuesta, Django desaprobó y eliminó la señal pre_syncdb
. He actualizado la respuesta para acomodar las versiones más recientes. Los mecanismos básicos son idénticos para las versiones más recientes, ya que ambos métodos se basan en las señales y en el código SQL que solo se ejecuta si no existe la extensión HSTORE.
Django 1.8+
Desde que Django introdujo las migraciones de DB, pre_syncdb
señales pre_syncdb
se marcaron en desuso en 1.7 y se eliminaron completamente en 1.9 . Sin embargo, introdujeron una nueva señal llamada pre_migrate
que puede usarse de la misma manera.
Ejemplo:
"""
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+ (respuesta original)
Una forma de asegurarse de que la extensión HSTORE se instale durante ./manage.py syncdb
es utilizar señales pre_syncdb
en su archivo models.py
que se introdujo con Django 1.6 .
Ejemplo:
"""
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.
Me parece que esto es útil si no desea ejecutarlo para cada nueva instancia de base de datos. Este método también funciona para las pruebas unitarias de Django durante la configuración de la base de datos de prueba.
Más información sobre los enlaces de señal en Django: https://docs.djangoproject.com/en/1.6/ref/signals/#management-signals
Django ahora incluye una operación de migración para crear la extensión hstore
en PostgreSQL :
from django.contrib.postgres.operations import HStoreExtension
class Migration(migrations.Migration):
...
operations = [
HStoreExtension(),
...
]
Finalmente descubrí que la extensión hstore no estaba instalada para la base de datos específica que estaba usando:
$ 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)
Pensé que una base de datos creada después de la instalación de hstore incluiría la extensión. No parece ser el caso, ¿ estoy malinterpretando cómo funcionan las extensiones? ¿Son específicos de la base de datos?