我考虑出于性能原因将我的站点后端从Postgres转移到Mongo,但是网站的关键部分依赖于GeoDjango模型来计算现实世界中对象之间的距离(等等)。
是否可以让大部分站点在Mongo上运行,但这些关键区域使用Postgres进行存储?这会很痛苦和/或容易出错吗?我有没有忽略掉一个完全基于Mongo的解决方案?
如果你能为我解答这些问题,我将不胜感激。
我考虑出于性能原因将我的站点后端从Postgres转移到Mongo,但是网站的关键部分依赖于GeoDjango模型来计算现实世界中对象之间的距离(等等)。
是否可以让大部分站点在Mongo上运行,但这些关键区域使用Postgres进行存储?这会很痛苦和/或容易出错吗?我有没有忽略掉一个完全基于Mongo的解决方案?
如果你能为我解答这些问题,我将不胜感激。
settings.py
中定义多个数据库连接。然后,您可以使用数据库路由器告诉Django应用程序透明地转到哪个数据库。
免责声明:这是我认为它应该工作的方式,我从未在Django中使用过MongoDB,也没有测试过我的代码是否实际有效。 :)
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
在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
...
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']
我建议看一下DjangoCan 2010的Disqus talk,了解他们的扩展架构。他们在Postgres上运行可能是最大的Django网站之一。他们提供简单的代码片段,展示如何使用Django内置的功能启动垂直和水平扩展。
据我了解,他们确实在某些分析方面使用MongoDB,但我不认为这在那次演讲中有讨论。
options.DEFAULT_NAMES =
? - Elias Prado