使用django 1.6的多个数据库,可以做出子查询"错误

时间:2015-11-25 00:20:23

标签: python mysql django

今天我尝试将我的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或查询集转换为列表,但这似乎非常低效,并且需要对我的代码进行大规模重构。

1 个答案:

答案 0 :(得分:0)

This bug已在cacheops 3.0中修复。该修复程序适用于任何路由器。