我之所以做出回应,是因为您的“我想知道是否有其他解决方案”的评论。有。我在一个网站上启动并运行它......一个应用程序的多个 SQLite 数据库。您还提到了 db router 问题,我也遇到了这些问题。
首先,将包含以下内容的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()没有带有属性的松鼠基类,这意味着可以很容易地使用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', ]。这通过router 引导查询,我们使用type() 函数在models.py 中初始化。特别注意,我没有在DATABASE_ROUTERS 中列出default 数据库。我确实有一个,它列在DATABASES 设置中,default 作为键。当您进行初始迁移时,各种 Django 应用程序表最终将保存在 default 数据库中,当然,默认情况下,Router() 将退到一边。
因此,在您的视图中,您将从Book.db = x 开始,其中视图签名将是myview(request, x, someothername):。您可能希望用try: finally: 覆盖整个视图主体,在finally 块中,您可以将数据库的选择恢复为默认值。
我必须承认,在迁移方面可能有美中不足。我讨厌那些,就我而言,每当我更新我的小 SQLite 数据库时,我都会重写它们的全部内容,这很频繁。因此,不必担心保存数据,只要我需要进行更改,我就会将它们和 Migrations 文件夹扔掉。但如果您的情况不同,您可能不得不使用migrate 和makemigrations 命令。我的每个数据库都有相同的模式,由模型定义。所以我实际上首先通过在DATABASES 设置中临时放置一个条目来创建一个空白数据库,该设置具有应用程序的名称作为键。我用它来创建 SQLite db 文件的一个副本,然后在我想添加一个新数据库时简单地复制它并重命名它(将新数据库的详细信息添加到 DATABASES 并删除具有 appname 的临时条目钥匙)。或者,您可能希望保留并充分利用 DATABASES 中的键是应用程序名称的数据库。
但遗憾的是,我们还没有完成。我必须修复admin.py。在admin.pyclass 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 注册模型的未回答问题。