Mezclando PostgreSQL y MongoDB (como backends Django)

Estoy pensando en cambiar el backend de mi sitio a Mongo de Postgres por razones de rendimiento, pero las partes clave del sitio se basan en los modelos de GeoDjango para calcular distancias entre objetos en el mundo real (y así sucesivamente).

¿Sería factible tener la mayor parte del sitio funcionando en Mongo, pero esas áreas clave que usan Postgres para el almacenamiento? ¿Es esto doloroso y / o propenso a errores? ¿Hay una solución de todo Mongo que me falta?

Cualquier luz que pueda arrojar sobre estos asuntos para mí sería muy apreciada.

Desde Django 1.2, puede definir múltiples conexiones de base de datos en su settings.py . Luego, puede usar los enrutadores de base de datos para decirle a Django a qué base de datos debe ir, de manera transparente para su aplicación.

Descargo de responsabilidad: así es como creo que debería funcionar, nunca he usado MongoDB en Django, ni he probado que mi código realmente funcione. 🙂

settings.py

 DATABASES = { 'default': { 'ENGINE': 'django_mongodb_engine', 'NAME': 'mydata', ... } 'geodata' { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'geodata', ... } } DATABASE_ROUTERS = ['path.to.ModelMetaRouter'] 

Modelos

Luego, agregue variables Meta personalizadas a sus tablas geográficas, para anular su base de datos. No agregue este atributo a los modelos que deben ir a la base de datos predeterminada.

 class SomeGeoModel(models.Model): ... class Meta: using = 'geodata' 

Enrutador de base de datos

Y escriba un enrutador de base de datos para dirigir todos los modelos que tienen el conjunto de atributos de uso, a la conexión apropiada:

 class ModelMetaRouter(object): def db_for_read(self, model, **hints): return getattr(model._meta, 'using', None) def db_for_write(self, model, **hints): return getattr(model._meta, 'using', None) def allow_relation(self, obj1, obj2, **hints): # only allow relations within a single database if getattr(obj1._meta, 'using', None) == getattr(obj2._meta, 'using', None): return True return None def allow_syncdb(self, db, model): if db == getattr(model._meta, 'using', 'default'): return True return None 

no puedes tener ‘usar’ en la lista Meta

Aquí hay una solución de trabajo.

agrega esto a los modelos.py:

  import django.db.models.options as options options.DEFAULT_NAMES = options.DEFAULT_NAMES + ('in_db',) 

Crea un router.py en tu carpeta de aplicaciones:

 myapp folder content: models.py router.py ... 

Contenido de router.py:

 class ModelMetaRouter(object): def db_for_read(self, model, **hints): db = getattr(model._meta, 'in_db', None) # use default database for models that dont have 'in_db' if db: return db else: return 'default' def db_for_write(self, model, **hints): db = getattr(model._meta, 'in_db', None) if db: return db else: return 'default' def allow_relation(self, obj1, obj2, **hints): # only allow relations within a single database if getattr(obj1._meta, 'in_db', None) == getattr(obj2._meta, 'in_db', None): return True return None def allow_syncdb(self, db, model): if db == getattr(model._meta, 'in_db', 'default'): return True return None 

Enrutador de referencia en su configuración:

  DATABASE_ROUTERS = ['myapp.router.ModelMetaRouter'] 

Me gustaría echar un vistazo a la charla Disqus de DjangoCan 2010 sobre su architecture de escalado. Posiblemente ejecuten el sitio web más grande de Django sobre Postgres. Presentan fragmentos de código simples que muestran cómo iniciar el escalado vertical y horizontal utilizando las características integradas en Django.

Tengo entendido que usan MongoDB para algunos de sus análisis analíticos, pero no creo que se haya discutido en esa charla.