今天我尝试将我的django站点设置为使用编写器/阅读器设置中的多个DB。切换后,我的代码使用一个QuerySet作为另一个的过滤器,我有时会得到可怕的"不能做子查询"错误信息。
我正在使用Django 1.6和Django Cacheops 2.4.3。看起来这个问题应该在Django Chacheops 2.4.1中修复。
settings.py:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': DB_NAME,
'USER': DB_USER,
'PASSWORD': DB_PASS,
'HOST': DB_HOST,
'PORT': '',
'OPTIONS': {
'init_command': 'SET storage_engine=INNODB',
}
},
'replica1': {
'ENGINE': 'django.db.backends.mysql',
'NAME': DB_NAME,
'USER': REPLICA_USER,
'PASSWORD': REPLICA_PASS,
'HOST': REPLICA_HOST,
'PORT': '',
}
}
DATABASE_ROUTERS = ['app_name.replica_router.ReplicaRouter']
APP_NAME / replica_router.py:
import random
class ReplicaRouter(object):
def db_for_read(self, model, **hints):
"""Reads go to a randomly chosen DB."""
return random.choice(['default', 'replica1'])
def db_for_write(self, model, **hints):
"""All writes go to default."""
return 'default'
def allow_relation(self, obj1, obj2, **hints):
"""Relations are allowed if both objects are in def/rep pool."""
db_list = ('default', 'replica1')
return obj1._state.db in db_list and obj2._state.db in db_list
def allow_syncdb(self, db, model):
return True
视图中违规代码的示例:
tokens = page_user.token_set.values_list('game_id', flat=True)
token_games = Game.objects.filter(id__in=tokens)
调用token_games.count()
会产生类似于以下内容的堆栈跟踪:
Internal Server Error: /user/999/1
Traceback (most recent call last):
File "/usr/local/bin/python2.7/site-packages/django/core/handlers/base.py", line 112, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/bin/python2.7/site-packages/django/contrib/auth/decorators.py", line 22, in _wrapped_view
return view_func(request, *args, **kwargs)
File "/Users/my_name/code/my_app/my_app/core/views.py", line 1879, in user_and_game
return display_user_page(request, uid, gid)
File "/Users/my_name/code/my_app/my_app/core/views.py", line 1719, in display_user_page
num_extra_badges = token_games.count() - 9
File "/usr/local/bin/python2.7/site-packages/cacheops/query.py", line 283, in count
return cached_as(self)(lambda: self._no_monkey.count(self))()
File "/usr/local/bin/python2.7/site-packages/cacheops/query.py", line 78, in cached_as
key_extra = [qs._cache_key() for qs in querysets]
File "/usr/local/bin/python2.7/site-packages/cacheops/query.py", line 137, in _cache_key
sql, params = self.query.get_compiler(self._db or DEFAULT_DB_ALIAS).as_sql()
File "/usr/local/bin/python2.7/site-packages/django/db/models/sql/compiler.py", line 94, in as_sql
where, w_params = self.query.where.as_sql(qn=qn, connection=self.connection)
File "/usr/local/bin/python2.7/site-packages/django/db/models/sql/where.py", line 106, in as_sql
sql, params = self.make_atom(child, qn, connection)
File "/usr/local/bin/python2.7/site-packages/django/db/models/sql/where.py", line 181, in make_atom
lvalue, params = lvalue.process(lookup_type, params_or_value, connection)
File "/usr/local/bin/python2.7/site-packages/django/db/models/sql/where.py", line 365, in process
connection=connection, prepared=True)
File "/usr/local/bin/python2.7/site-packages/django/db/models/fields/__init__.py", line 399, in get_db_prep_lookup
sql, params = value._as_sql(connection=connection)
File "/usr/local/bin/python2.7/site-packages/django/db/models/query.py", line 1051, in _as_sql
raise ValueError("Can't do subqueries with queries on different DBs.")
ValueError: Can't do subqueries with queries on different DBs.
[24/Nov/2015 16:03:44] "GET /user/999/1 HTTP/1.1" 500 144360
有没有人有任何指针?到目前为止,我能找到的最好的事情是在过滤之前将任何values_list或查询集转换为列表,但这似乎非常低效,并且需要对我的代码进行大规模重构。