django一个应用程序一个模型多个数据库




我是django-webapp开发的新手,遇到了一个问题。我已经创建了一个具有1个模型的应用程序,以便使用1个表单将数据插入数据库。我将使用多个数据库。每个数据库将有一个具有相同结构的表(目前)。现在我的问题是:

如何对多个数据库及其各自的表仅使用一个模型、一个视图和一个表单。数据库和表应该在调用各自的url时进行切换

例如。http://www.example.com/x/abc/将访问第一个数据库及其所有操作的表
http://www.example.com/y/abc/将访问第二个数据库

我已经尝试了django文档中提供的示例数据库路由,但没有多大帮助。我也找不到解决这个特定问题的相关帖子/问题

我想这样做是因为稍后我将添加更多的模型和表单来访问数据库表中的数据,这对我来说似乎是最干净的方法

PS:我正在使用django 1.9.6

无论这是否是构建应用程序的好方法,您都可以使用:告诉Django使用读写哪个数据库

Person.objects.using('db1').create(...)
Person.objects.using('db2').create(...)

因此,您不需要使用路由器,只需在设置中定义这两个数据库,并在两者上运行migrate即可。您的模型表将在每个数据库中创建,在您的代码中,您可以根据您选择的任何逻辑(例如,根据请求路径)从这两个数据库中读取和写入。

请参阅https://docs.djangoproject.com/en/1.9/topics/db/multi-db/#manually-选择a数据库

我之所以回复,是因为您的"我想知道是否有其他解决方案"评论。有。我在一个网站上安装并运行了它。。。多个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()没有带属性的蠕动基类,这意味着Pythontype函数可以很容易地克隆它;并且,(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', ]。这将引导查询通过我们在models.py中使用type()函数初始化的router。特别要注意的是,我没有在DATABASE_ROUTERS中列出default数据库。我确实有一个,它列在DATABASES设置中,以default为键。当您进行初始迁移时,各种Django应用程序表将最终出现在default数据库中,当然默认情况下,因为Router()将退出。

因此,在您的视图中,您将从Book.db = x开始,其中视图签名将是myview(request, x, someothername):。您可能希望用try: finally:覆盖整个视图主体,其中在finally块中,您会将数据库的选择返回到某个默认值。

我必须承认,在移民问题上可能有美中不足之处。我讨厌这些,在我的情况下,每当我更新我的小SQLite数据库时,我都会重写它们的全部内容,这是经常发生的。因此,由于不关心保存数据,每当需要进行更改时,我都会将它们和迁移文件夹丢弃。但是,如果您的情况不同,您可能不得不使用migratemakemigrations命令。根据模型的定义,我的每个数据库都有相同的模式。因此,我实际上首先通过在DATABASES设置中临时放置一个条目来创建一个空白数据库,该条目将应用程序的名称作为关键字。我用它创建了SQLite数据库文件的一个副本,然后当我想添加一个新数据库时,简单地复制并重命名它(将新数据库的详细信息添加到DATABASES中,并删除以appname为键的临时条目)。或者,您可能希望保留并充分利用DATABASES中的密钥是应用程序名称的数据库。

但遗憾的是,我们还没有结束。我不得不修复admin.py。在admin.pyclass BookAdmin(admin.ModelAdmin):中创建后,按照通常的方式,您将无法在admin中找到可访问的两个数据库。所以我的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对模型进行子类注册的问题。

相关内容

最新更新