django 多数据库路由不适用于多个模式

标签 django oracle orm django-models django-orm

我在 oracle 后端运行 django。我需要使用两种模式 - 一种用于遗留数据库,另一种用于所有 django 相关表。

所以这是我的设置。数据库:

APPS_DB = 'apps'
DATABASES = {

    'default' : { 
        'ENGINE': 'django.db.backends.oracle'
        'NAME': 'django',                      
        'USER': 'django-tables',                      
        'PASSWORD': '****',                  
        'HOST': 'localhost',                       
        'PORT': '1531',                     
    },

    APPS_DB : { 
        'ENGINE': 'django.db.backends.oracle', 
        'NAME': 'django',                      
        'USER': 'legacy-stuff',                      
        'PASSWORD': '****',                 
        'HOST': 'localhost',                     
        'PORT': '1531',                      
     },
}

我还定义了路由器:
class MyRouter(object):
    """A router to control all database operations on models"""

def __init__(self):
    aux = []
    for app in settings.INSTALLED_APPS:
        if not app.endswith('myapp'):
            aux.append(app)
    self.djangoStuff = tuple(map(lambda x: x[x.rfind('.')+1:], aux))

def is_django_stuff(self, model):
    return model._meta.app_label in self.djangoStuff

def db_for_read(self, model, **hints):
    "Point all django apps models to separate DB"
    logger.info("READ from " + model._meta.app_label)
    if self.is_django_stuff(model):
        logger.info("Will be directed to default DB")
        return None
    logger.info("Will be directed to legacy DB")    
    return settings.APPS_DB

def db_for_write(self, model, **hints):
    "Point all django apps models to separate DB"
    logger.info("WRITE")
    if self.is_django_stuff(model):
        return None
    return settings.APPS_DB

def allow_relation(self, obj1, obj2, **hints):
    "Allow any relation"
    logger.info("ALLOW REL")
    return True

def allow_syncdb(self, db, model):
    "Allow syncdb for all managed objects"
    logger.info("ALLOW SYNC")
    if db == 'default' and self.is_django_stuff(model):
        return True
    if db != 'default' and not self.is_django_stuff(model):
        return True
    return False

现在我有非常简单的模型:
class Poll(models.Model):
    question = models.CharField(max_length=200)
    user = models.ForeignKey(User)
    pub_date = models.DateTimeField('date published')

我做了两个同步数据库:
python manage.py syncdb
python manage.py syndb --database apps

一切顺利。
然后我使用“python manage.py shell”创建轮询对象
superuser = User.objects.all()[0]
p = Poll(question="foo", user = superuser, pub_date = datetime.now())
p.save()

我尝试从民意调查中检索用户:
  a = Poll.objects.all()
  b = len(a)
  b = a[0]
  c = b.artist

我在路由器中启用了日志记录,所以我看到最后一个查询将被定向到正确的数据库:
READ from myapp
Will be directed to apps DB
READ from myapp
Will be directed to apps DB
READ from auth
Will be directed to default DB

我什至可以看到实际的 SQL 语句:
(0.005) SELECT "AUTH_USER"."ID", "AUTH_USER"."USERNAME", "AUTH_USER"."FIRST_NAME",    "AUTH_USER"."LAST_NAME", "AUTH_USER"."EMAIL", "AUTH_USER"."PASSWORD", "AUTH_USER"."IS_STAFF", "AUTH_USER"."IS_ACTIVE", "AUTH_USER"."IS_SUPERUSER", "AUTH_USER"."LAST_LOGIN", "AUTH_USER"."DATE_JOINED" FROM "AUTH_USER" WHERE "AUTH_USER"."ID" = :arg0 ; args=(1,)

但我收到错误:
  File "<console>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/Django-1.4.1-py2.7.egg/django/db/models/fields/related.py", line 350, in __get__
    rel_obj = qs.get(**params)
  File "/usr/local/lib/python2.7/dist-packages/Django-1.4.1-py2.7.egg/django/db/models/query.py", line 361, in get
    num = len(clone)
  File "/usr/local/lib/python2.7/dist-packages/Django-1.4.1-py2.7.egg/django/db/models/query.py", line 85, in __len__
    self._result_cache = list(self.iterator())
  File "/usr/local/lib/python2.7/dist-packages/Django-1.4.1-py2.7.egg/django/db/models/query.py", line 291, in iterator
    for row in compiler.results_iter():
  File "/usr/local/lib/python2.7/dist-packages/Django-1.4.1-py2.7.egg/django/db/models/sql/compiler.py", line 763, in results_iter
    for rows in self.execute_sql(MULTI):
  File "/usr/local/lib/python2.7/dist-packages/Django-1.4.1-py2.7.egg/django/db/models/sql/compiler.py", line 818, in execute_sql
    cursor.execute(sql, params)
  File "/usr/local/lib/python2.7/dist-packages/Django-1.4.1-py2.7.egg/django/db/backends/util.py", line 40, in execute
return self.cursor.execute(sql, params)
  File "/usr/local/lib/python2.7/dist-packages/Django-1.4.1-py2.7.egg/django/db/backends/oracle/base.py", line 675, in execute
    return self.cursor.execute(query, self._param_generator(params))
DatabaseError: ORA-00942: table or view does not exist

所以我的问题是 - 我做错了什么?

最佳答案

跨数据库外键本质上是无效的,因为 Django 正在建模一个具有参照完整性的“适当”关系数据库,如果模型存储在完全不同的物理存储中,则无法在数据库级别强制执行。

无论如何,出于这个原因,Django 必须假设任何对象都与您最初检索的对象存在于同一数据库中。在您的情况下,它从您的旧数据库中获取您的 Poll 对象,因此它也必须在那里寻找您的用户(或艺术家或其他任何人)。

对于像这样的简单查询,很容易解决,例如:

poll = Poll.objects.all()[0]
user_id = poll.user_id # _id after the name of your "Foreign Key" field - which cannot really be an FK
user = User.objects.get(user_id) # This will be a new query and can use a different database, it will check the router

对于更复杂的查询(连接等),您经常会发现需要构建列表或 id 集,并使用 filter(id__in=your_list_of_ids) 进行查询。

根据记录的数量,这样做可能会导致性能或内存使用量的损失。 (但在某些情况下,您的查询实际上比原始连接快得多,这完全取决于您的应用程序。)您可能需要将 id 列表分成批次,否则您的查询可能会变得太长等等。但没有这些问题都是不可逾越的。

当您处理来自另一个数据库的 id 时,由您来强制执行参照完整性。有时您需要设置批处理来处理整理数据。

这一切听起来都是错误的,但这种关注点分离,特别是如果您可以限制依赖关系,并且仅在一个方向上,可能是完全正确的方法。

关于django 多数据库路由不适用于多个模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12862541/

相关文章:

java - 尝试使用 spring 和 hibernate 用户 oracle db 时出错

python - 通过相关对象权限的 Django 权限

oracle - 我可以对交互式网格行删除进行验证吗?

sql - 如何获取受存储过程影响的记录数?

python - 删除未级联到sqlalchemy中的表

c# - 哪个ORM支持多行更新和删除

java - hibernate 。无法保存使用 classForName 生成并声明为其父类(super class)的对象(多态性)

django-compressor:在 Debug模式下使用lessc

python - 如何将主服务器数据库中的所有数据复制到本地sqlite数据库以供本地使用?

django - virtualenv 返回错误 'Operation not Permitted'