我响应,因为你的“我想知道是否有另一种解决方案”的评论的。有。我有它在网站上运行...多个SQLite数据库与一个应用程序。你也提到了数据库路由器问题,我也在努力。
首先,把任何地方router.py
文件,该文件包含以下内容:
class Router(object):
appname = ''
def db_for_read(self, model, **hints):
"""
Attempts to read self.appname models go to model.db.
"""
if model._meta.app_label == self.appname:
return model.db
return None
def db_for_write(self, model, **hints):
"""
Attempts to write self.appname models go to model.db.
"""
if model._meta.app_label == self.appname:
return model.db
return None
def allow_relation(self, obj1, obj2, **hints):
"""
Allow relations if a model in the self.appname app is involved.
"""
if obj1._meta.app_label == self.appname or \
obj2._meta.app_label == self.appname:
return True
return None
# This is possibly the new way, for beyond 1.8.
'''
def allow_migrate(self, db, app_label, model_name=None, **hints):
"""
Make sure the self.appname app only appears in the self.appname
database.
"""
if app_label == self.appname:
return db == self.appname
return None
'''
# Contrary to Djano docs this one works with 1.8, not the one above.
def allow_migrate(self, db, model):
"""
Make sure the self.appname app only appears in the self.appname
database.
"""
if db == self.appname:
return model._meta.app_label == self.appname
elif model._meta.app_label == self.appname:
return False
return None
我只使用Django 1.8测试这一点;正如你使用1.9,根据文档,至少必须使用其他allow_migrate
。
特别要注意的是:(1)没有带有属性的Router()的squirously基类,这意味着Python type
函数可以很容易地用来克隆它; (2)很明显,当前模型实例可以通过外部命名空间在Router()
内部访问。
所以,现在,在你的models.py
,这样做:
from django.db import models
import os
appname = os.path.dirname(__file__).split('/')[-1]
from dirwhereyouputtherouter.router import Router
router = type(appname, (Router,), dict(appname=appname))
class Book(models.Model):
# This is the default, for use when there is only one db per app.
db = appname
# the various fields here, etc.
做到这一点对每个模型。然后Router()
当遇到任何查询将return model.db
。我在这里选择,在我的方案中,让应用程序的默认Django方案从其目录的名称中获取它的名称。
现在,在settings.py
中,您需要DATABASE_ROUTERS = [ 'appdir.models.router', ]
。这指示通过使用type()
函数在models.py
中初始化的router
查询。特别要注意的是,我没有在DATABASE_ROUTERS
列出default
数据库。我确实有一个,它在DATABASES
设置中列出,其中default
为关键。当您进行初始迁移时,各种Django应用程序表最终将在default
数据库中结束,当然,因为Router()
将退出。
因此,在您的视图中,您将从Book.db = x
开始,其中视图签名为myview(request, x, someothername):
。有一个机会,你可能想要在finally
块中使用try: finally:
来填充整个视图体,你可以将数据库的选择返回到某个默认值。
我必须承认,当涉及到迁移时,软膏中可能会有苍蝇。我讨厌那些,在我的情况下,我会在我更新它们的时候写下我的小SQLite数据库的全部内容,这经常是这样。所以,不用担心保存数据,只要需要进行更改,我就会将它们和Migrations文件夹丢弃。但是如果你的情况不同,你可能不得不努力与migrate
和makemigrations
命令。我的每个数据库都具有相同的模式,由模型定义。所以我实际上首先创建了一个空白数据库,临时在DATABASES
设置中输入一个与应用程序名称相同的条目。我用它创建SQLite数据库文件的一个副本,然后只需复制它并在我想添加新数据库时将其重命名(将新数据库的详细信息添加到DATABASES
并删除以appname作为关键字的临时条目)。或者,您可能希望保留并善用其DATABASES
中的密钥是应用程序名称的数据库。
但遗憾的是,我们没有完成。我不得不修复admin.py
。在admin.py
class BookAdmin(admin.ModelAdmin):
中创建之后,按照通常的方式,您将无法在管理员中找到您的两个数据库。所以我admin.py
样子:
from django.contrib import admin
from django.conf import settings
import os
class BookAdmin(admin.ModelAdmin):
list_display = ...
list_filter = ...
etc.
from models import Book
appname = os.path.dirname(__file__).split('/')[-1]
dbkeys = settings.DATABASES.keys()
while 'default' in dbkeys: dbkeys.remove('default')
dbkeys = [ k for k in dbkeys if os.path.dirname(settings.DATABASES[k]['NAME']).split(os.sep)[-1] == appname ]
for dbname in dbkeys:
if dbname == dbkeys[0]:
class Book_(Book):
class Meta:
proxy = True
verbose_name = Book.__name__ + '_' + ''.join('_' + x.capitalize() or '_' for x in dbname.split('_'))
verbose_name_plural = Book.__name__ + 's_'+ ''.join('_' + x.capitalize() or '_' for x in dbname.split('_'))
db_table = appname + '_book'
Book_.db = dbname
Book_.__name__ = Book.__name__ + '_' + appname.capitalize() + '_' + ''.join('_' + x.capitalize() or '_' for x in dbname.split('_'))
admin.site.register(Book_, BookAdmin)
elif dbname == dbkeys[1]:
class Book__(Book):
class Meta:
proxy = True
verbose_name = Book.__name__ + '_' + ''.join('_' + x.capitalize() or '_' for x in dbname.split('_'))
verbose_name_plural = Book.__name__ + 's_'+ ''.join('_' + x.capitalize() or '_' for x in dbname.split('_'))
db_table = appname + '_book'
Book__.db = dbname
Book__.__name__ = Book.__name__ + '_' + appname.capitalize() + '_' + ''.join('_' + x.capitalize() or '_' for x in dbname.split('_'))
admin.site.register(Book__, BookAdmin)
这工作,因为我把数据库文件在该应用程序的文件夹中的每个应用程序。对不起,这一切都有点棘手。我有很好的理由想要这个能力。另请参阅我未回答的有关子分类模型的问题,以便使用admin.site.register
,here进行注册。
而且你必须有单独的数据库,因为......?您是否考虑过使用URL路径段作为标识符的替代方法,并将该标识符用作外键来过滤数据? – Brandon
,因为它们里面的表格将具有相同的结构,但具有不同的数据,现在的URL不是一个大问题。问题在于“1个模型,1个视图和1个多个数据库的表单”,以避免大量的重复。 – rrawat
如果数据不同,它会有什么不同?它都是通过外键分隔的。外键方法将您的复杂度降低了一个数量级。 – Brandon