【问题标题】:Avoid making multiple Django database calls避免进行多次 Django 数据库调用
【发布时间】:2020-10-09 18:30:11
【问题描述】:

我想查询我的 Django 数据库一次并返回一个查询集(分配了名称“代码”),我可以对其进行迭代以获得每个实例的“内部代码”属性,而无需进一步调用数据库。这是我的代码,但我不确定是否每次在 Queryset 上使用“get”时都在查询数据库,以及如何避免这种情况:

codes = models.RecordType.objects.all()

permanent = sorted([
    (
        codes.get(
            industry_code=category.value
        ).internal_code,
        self.labels.get(category, category.name)
    )
    for category in enums.Category
])

【问题讨论】:

  • 我不是 Djangonaut,但对我来说是你进行单个查询并使用返回的查询集
  • 使用RecordType.objects.values_list('internal_code', flat=True)只得到internal_code列返回列表样式,然后你可以zip与类别获取元组列表,这在imo中更具可读性。

标签: python sql django database loops


【解决方案1】:

如果您想强制评估 QuerySet,您可以这样做:

codes = list(models.RecordType.objects.all())

【讨论】:

    【解决方案2】:

    你写的大致是这样,但你不应该一直打电话给get()。每次执行此操作时,您都在进行单独的数据库查询。

    当你表明你想要结果时,Django 会懒惰地从数据库中获取。例如

    # first enable some logging to see the database queries
    import logging.config
    logging.config.dictConfig({
        'version': 1,
        'formatters': {
            'simple': {'format': '%(levelname)s %(message)s'},
        },
        'handlers': {
            'console': {
                'level': 'DEBUG',
                'class': 'logging.StreamHandler',
                'formatter': 'simple',
            },
        },
        'root': {
            'level': 'WARNING',
            'handlers': ['console'],
        },
        'loggers': {
            'django.db.backends': {'level': 'DEBUG',},
        },
    })
    
    
    # No query made
    codes = RecordType.objects.filter(
        industry_code__in=[cat.value for cat in enums.Category]
    )
    
    # show the query that will be made (roughly)
    print(str(codes.query))
    
    # force the queryset to be executed and return all the results.
    # the queryset is executed when you iterate over it.
    codes_by_industry_code = {
        code.industry_code: code
        for code in codes
    }
    
    # now you can set up your list:
    permanent = [
        (
            codes_by_industry_code[category.value].internal_code,
            self.labels.get(category, category.name)
        )
        for category in enums.Category
    ]
    

    现在,如果您想确保查询只发生在正确的位置,您应该使用this question 中描述的测试工具来测试您的代码。这是确保您的代码在数据库查询方面执行应有的工作的唯一方法。

    【讨论】:

      【解决方案3】:

      __in 运算符用于filter 所有RecordTypeindustry_code 出现在Category 枚举中:

      codes = (
          RecordType.objects
          .filter(industry_code__in=[c.value for c in Category])
          .only('industry_code', 'internal_code')
      )
      category_labels = {c.value: self.labels.get(c, c.name) for c in Category}
      
      permanent = sorted([
          (code.internal_code, category_labels[code.industry_code])
          for code in codes
      ])
      

      使用.only 以防RecordType 有很多不需要的字段。

      但我不确定是否每次在查询集上使用“get”时都在查询数据库

      是的。您可以链接.filter().exclude() 和其他返回查询集而不运行它的方法;使用.get() 会立即(并且每次)评估查询集,并返回一个实例。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-06-14
        • 2020-11-13
        • 2017-05-24
        • 2014-06-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多