混合使用PostgreSQL和MongoDB(作为Django后端)

15

我考虑出于性能原因将我的站点后端从Postgres转移到Mongo,但是网站的关键部分依赖于GeoDjango模型来计算现实世界中对象之间的距离(等等)。

是否可以让大部分站点在Mongo上运行,但这些关键区域使用Postgres进行存储?这会很痛苦和/或容易出错吗?我有没有忽略掉一个完全基于Mongo的解决方案?

如果你能为我解答这些问题,我将不胜感激。

3个回答

10
自Django 1.2起,您可以在settings.py定义多个数据库连接。然后,您可以使用数据库路由器告诉Django应用程序透明地转到哪个数据库。 免责声明:这是我认为它应该工作的方式,我从未在Django中使用过MongoDB,也没有测试过我的代码是否实际有效。 :)

settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django_mongodb_engine',
        'NAME': 'mydata',
        ...
    }
    'geodata' {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'geodata',
        ...
    }
}

DATABASE_ROUTERS = ['path.to.ModelMetaRouter']

模型

然后,将自定义元变量添加到您的地理表中,以覆盖其数据库。不要将此属性添加到应该进入默认数据库的模型中。

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

数据库路由器

编写一个数据库路由器,将所有具有设置了using元属性的模型指向适当的连接:

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

2

在Meta列表中不能使用'using'。

以下是可行的解决方案:

将以下内容添加到models.py中:

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

在您的应用程序文件夹中创建一个名为 router.py 的文件:

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

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

在设置中引用路由器:

   DATABASE_ROUTERS = ['myapp.router.ModelMetaRouter']

1
这个可以运行,但我不理解它,如何/为什么?有什么神奇的原理在其中? - vijay shanker
但是你在哪里添加 options.DEFAULT_NAMES = - Elias Prado

1

我建议看一下DjangoCan 2010的Disqus talk,了解他们的扩展架构。他们在Postgres上运行可能是最大的Django网站之一。他们提供简单的代码片段,展示如何使用Django内置的功能启动垂直和水平扩展。

据我了解,他们确实在某些分析方面使用MongoDB,但我不认为这在那次演讲中有讨论。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接