6

Oracleバックエンドでdjangoを実行しています。2 つのスキーマを使用する必要があります。1 つはレガシー DB 用、もう 1 つはすべての 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')

2 つの syncdb を作成します。

python manage.py syncdb
python manage.py syndb --database apps

すべてがうまくいきます。次に、'python manage.py shell' を使用して poll オブジェクトを作成します。

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

ルーターでログを有効にしているので、最後のクエリが正しい DB に送信されることがわかります。

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

だから私の質問は - 私が間違っているのは何ですか?

4

1 に答える 1

3

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 を扱う場合、参照整合性を強制するのはあなた次第です。場合によっては、データの整理に対処するためにバッチ プロセスを設定する必要があります。

これはすべて間違っているように聞こえますが、特に依存関係を制限し、一方向だけに保つことができる場合、そのような懸念の分離は正確に正しいアプローチになる可能性があります.

于 2012-10-21T21:23:50.870 に答える