代码之家  ›  专栏  ›  技术社区  ›  Gady

Django有多个数据库,“无法在只读事务中执行”错误

  •  1
  • Gady  · 技术社区  · 12 年前

    我使用了 Django docs 以主从配置设置多个数据库。我的路由器设置正确,我可以看到读取和写入到正确的相应数据库,但我的一些API调用遇到了错误:

    cannot execute [UPDATE or DELETE] in a read-only transaction

    在发生这种情况的API处理程序中,作为同一调用的一部分,我正在更新或删除一些其他模型,Django似乎希望为这些事务使用从属数据库,而不是主数据库。

    A workaround I found 是要链接 .using('default') 之前 update() 或 delete() ,这基本上迫使Django使用主数据库进行更新或删除。但这感觉很粗糙,有点像绷带,所以我想确保没有更好的方法来做到这一点。

    非常感谢任何帮助。

    3 回复  |  直到 12 年前
        1
  •  2
  •   Medhat Gayed    12 年前

    你试过以下方法吗?这是从Django文档页面复制的:

    import random
    
    class MasterSlaveRouter(object):
        def db_for_read(self, model, **hints):
            """
            Reads go to a randomly-chosen slave.
            """
            return random.choice(['slave1', 'slave2'])
    
        def db_for_write(self, model, **hints):
            """
            Writes always go to master.
            """
            return 'master'
    
        def allow_relation(self, obj1, obj2, **hints):
            """
            Relations between objects are allowed if both objects are
            in the master/slave pool.
            """
            db_list = ('master', 'slave1', 'slave2')
            if obj1._state.db in db_list and obj2._state.db in db_list:
                return True
            return None
    
        def allow_migrate(self, db, model):
            """
            All non-auth models end up in this pool.
            """
            return True
    

    最后,在设置文件中,我们添加了以下内容(将path.to替换为定义路由器的模块的实际python路径):

    DATABASE_ROUTERS = ['path.to.AuthRouter', 'path.to.MasterSlaveRouter']
    
        2
  •  0
  •   Gady    12 年前

    看起来没有办法不喷洒 .using('default') 周围的代码。

        3
  •  0
  •   Alexandr Shutko    5 年前

    我也收到了这封信,并为django开发者贴了一张罚单。 这里是: https://code.djangoproject.com/ticket/32965

    有一个答案。django文档称.delete()和.update()使用用于检索对象的相同数据库(始终只读!)。所以这不是一个bug,而是未来,因为他们说它有文档记录。

    因此,有两种方法可以解决这个问题:

    1. 在每个.delete()和.update()之前添加using('xxxx')
    2. 用.clear()替换.delete(),用.set()替换.update()