mno*_*tka 6 oracle django orm django-models django-orm
我有django在oracle后端运行.我需要使用两个模式 - 一个用于遗留DB,第二个用于所有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',
},
}
Run Code Online (Sandbox Code Playgroud)
我还定义了路由器:
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
Run Code Online (Sandbox Code Playgroud)
现在我有一个非常简单的模型:
class Poll(models.Model):
question = models.CharField(max_length=200)
user = models.ForeignKey(User)
pub_date = models.DateTimeField('date published')
Run Code Online (Sandbox Code Playgroud)
我做了两个syncdbs:
python manage.py syncdb
python manage.py syndb --database apps
Run Code Online (Sandbox Code Playgroud)
一切都很顺利.然后我使用'python manage.py shell'创建poll对象
superuser = User.objects.all()[0]
p = Poll(question="foo", user = superuser, pub_date = datetime.now())
p.save()
Run Code Online (Sandbox Code Playgroud)
我尝试从民意调查中检索用户:
a = Poll.objects.all()
b = len(a)
b = a[0]
c = b.artist
Run Code Online (Sandbox Code Playgroud)
我在路由器中启用了日志记录,因此我看到最后一个查询将被定向到正确的数据库:
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
Run Code Online (Sandbox Code Playgroud)
我甚至可以看到实际的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,)
Run Code Online (Sandbox Code Playgroud)
但是我收到了错误:
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
Run Code Online (Sandbox Code Playgroud)
所以我的问题是 - 我做错了什么?
跨数据库外键本质上是无效的,因为 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
Run Code Online (Sandbox Code Playgroud)
对于更复杂的查询(连接等),您经常会发现需要构建列表或 id 集,并使用 filter(id__in=your_list_of_ids) 进行查询。
根据记录的数量,执行此操作可能会导致性能或内存使用量下降。(但在某些情况下,您的查询实际上会比原始连接快得多,这完全取决于您的应用程序。)您可能需要将 id 列表分成批次,否则您的查询可能会变得太长,等等。但没有这些问题都是无法克服的。
当您处理来自另一个数据库的 id 时,您需要强制执行引用完整性。有时您需要设置批处理来处理整理数据。
这一切听起来都是错误的,但这种关注点分离,特别是如果您可以限制依赖关系,并且只在一个方向上,则可能是完全正确的方法。