首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >django多数据库路由不适用于多个模式

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

Stack Overflow用户
提问于 2012-10-12 23:38:19
回答 1查看 2K关注 0票数 6

我让django在oracle后台运行。我需要使用两个模式-一个用于遗留DB,另一个用于所有与django相关的表。

这就是我的settings.DATABASES:

代码语言:javascript
运行
复制
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',                      
     },
}

我还定义了路由器:

代码语言:javascript
运行
复制
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

现在我有了一个非常简单的模型:

代码语言:javascript
运行
复制
class Poll(models.Model):
    question = models.CharField(max_length=200)
    user = models.ForeignKey(User)
    pub_date = models.DateTimeField('date published')

我创建了两个syncdb:

代码语言:javascript
运行
复制
python manage.py syncdb
python manage.py syndb --database apps

一切都很顺利。然后,我使用'python manage.py shell‘创建了投票对象

代码语言:javascript
运行
复制
superuser = User.objects.all()[0]
p = Poll(question="foo", user = superuser, pub_date = datetime.now())
p.save()

我尝试从投票中检索用户:

代码语言:javascript
运行
复制
  a = Poll.objects.all()
  b = len(a)
  b = a[0]
  c = b.artist

我在路由器中启用了日志记录,因此我看到最后一个查询将被定向到正确的DB:

代码语言:javascript
运行
复制
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语句:

代码语言:javascript
运行
复制
(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,)

但是我得到了一个错误:

代码语言:javascript
运行
复制
  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

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-10-22 05:23:51

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

无论如何,由于这个原因,Django必须假设任何对象都存在于您最初检索到的数据库中。在您的例子中,它从您的遗留数据库中获取了Poll对象,因此它也必须在那里查找您的用户(或艺术家或其他任何人)。

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

代码语言:javascript
运行
复制
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

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

根据记录数的不同,这样做可能会对性能或内存使用造成影响。(但在某些情况下,您的查询实际上会比原始连接快得多,这完全取决于您的应用程序。)你可能需要把你的id列表分成几批,或者你的查询可能会变得太长,等等,但是这些问题都不是无法克服的。

当您处理来自另一个数据库的id时,应该由您来执行引用完整性。有时,您需要设置批处理过程来处理整理数据。

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

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12862541

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档