【问题标题】:Django: Database used for prefetch_related is not the same that the parent queryDjango:用于 prefetch_related 的数据库与父查询不同
【发布时间】:2016-10-19 19:10:55
【问题描述】:

我在我的 Django 应用程序中使用了一个多数据库,其中包含一个主数据库和一个只读副本,但为了避免复制滞后问题,路由器总是使用默认数据库,除了我手动设置数据库的少数地方。

我遇到了一个问题,因为我不知道如何指定用于 prefetch_related 的数据库。

例如,我希望下一个查询仅使用 read_replica DB,但它执行 2 个查询,第一个查询按预期转到 read_replica,第二个转到 default DB。

users = UserProfile.objects.using('read_replica').prefetch_related('usermedia_set').filter(id__in=user_ids)

这是此查询的输出:

选择@@SQL_AUTO_IS_NULL; args=无

选择版本(); args=无

SELECT ... FROM ftmanager_userprofile WHERE (ftmanager_userprofile.id IN (33); args=(33,)

选择@@SQL_AUTO_IS_NULL; args=无

选择版本(); args=无

选择...从ftmanager_usermedia WHERE ftmanager_usermedia.user_id IN (33); args=(33,)

我在Django tickets 上看到了相关票证,但我不明白如何将using() 应用于内部查询集。

【问题讨论】:

    标签: python django orm database-replication


    【解决方案1】:

    我找到了考虑Django票证的解决方案,你需要使用Prefetch类来定义prefetch_related使用的内部查询集,它确实把代码弄乱了但收获是值得的:

    from django.db.models.query import Prefetch
    users = UserProfile.objects.using('read_replica').prefetch_related(Prefetch('usermedia_set', queryset=UserMedia.objects.using('read_replica'))).filter(id__in=user_ids)
    

    【讨论】:

      【解决方案2】:

      我也遇到了同样的问题。配置路由器(即 db_for_read 并使用提示中的实例)有帮助:

      def db_for_read(self, model, **hints):
          instance = hints.get('instance')
          if instance is not None:
              if instance._meta.app_label in self.route_app_labels:
                  return self.route_db_name 
          elif model._meta.app_label in self.route_app_labels:
              return self.route_db_name 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-16
        • 2015-01-06
        • 1970-01-01
        • 2012-05-09
        • 2018-10-16
        相关资源
        最近更新 更多