Я отвечаю из-за вашего «мне было интересно, действительно ли есть другое решение» комментарий. Там есть. У меня есть и работает на веб-сайте ... несколько баз данных SQLite с одним приложением. Вы также упомянули проблемы с маршрутизатором db, с которыми я тоже боролся.
Во-первых, разместить в любом месте в 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
, который мы инициализировали в models.py
, используя функцию type()
. Обратите внимание, что я не перечисляю базу данных default
здесь, в DATABASE_ROUTERS
. У меня есть один, который указан в настройке DATABASES
с ключом default
. Когда вы выполняете свои первоначальные миграции, различные таблицы приложений Django попадают в базу данных default
, по умолчанию, конечно, так как Router()
отступит.
Итак, в вашем представлении вы начнете с Book.db = x
, где будет отображаться подпись вида myview(request, x, someothername):
. Есть вероятность, что вы захотите задрапировать весь корпус тела с помощью try: finally:
, где в блоке finally
вы вернете выбор базы данных по умолчанию.
Должен признаться, что может произойти муха в мазе, когда дело доходит до миграции. Я ненавижу их, и в моем случае я пишу все содержимое моих маленьких баз данных SQLite, когда я их обновляю, что часто. Поэтому, не заботясь о сохранении данных, я бросаю их и папки Migrations, когда мне нужно вносить изменения. Но если ваши обстоятельства разные, вам, возможно, придется бороться с командами migrate
и makemigrations
. Каждая из моих баз данных имеет одинаковую схему, определенную моделью. Поэтому я фактически создал пустую базу данных, сначала временно помещая запись в настройку DATABASES
, которая имела в качестве ключа имя приложения. Я использовал это, чтобы создать одну копию файла SQLite db, а затем просто скопировал его и переименовал, когда захотел добавить новую базу данных (добавив данные для новой базы данных в DATABASES
и удалив временную запись с именем приложения в качестве ключа). Кроме того, вы можете сохранить и использовать базу данных, ключ которой находится в DATABASES
- это имя приложения.
Но, к сожалению, мы не закончили. Я должен был исправить admin.py
. После создания в admin.py
class 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
, here.
и у вас должны быть отдельные базы данных, потому что ...? Вы рассматривали альтернативу использования сегмента пути URL как идентификатора и использования этого идентификатора в качестве внешнего ключа для фильтрации данных? – Brandon
, потому что таблицы внутри них будут иметь одинаковую структуру, но разные данные, URL прямо сейчас не является большой проблемой. проблема заключается в «1 модели, 1 представлении и 1 форме для нескольких баз данных», чтобы избежать много дублирования. – rrawat
Какая разница, если данные разные? Все это разделено внешним ключом. Подход внешнего ключа уменьшает вашу сложность на порядок. – Brandon