【问题标题】:Use Django ORM values and call member functions使用 Django ORM 值并调用成员函数
【发布时间】:2018-07-11 12:08:08
【问题描述】:

我的 Django 应用中有以下模型。

class Revenue(models.Model):
    from_a = models.IntegerField()
    from_b = models.IntegerField()

    def get_total(self):
        return self.from_a + self.from_b

现在我正在使用 Revenue.objects.filter(from_a__gt = 10).values('from_a', 'from_b') 检索数据。

从上面的查询集中我得到了值,现在我想在对象上调用get_total 函数。 我没有找到调用该函数的方法。

有没有办法只使用values 检索我需要的数据,并且还可以调用这些对象的member_functions

如果我的模型有 100 列列,Revenue.objects.filter(from_a__gt = 10) 不应该是解决方案。

【问题讨论】:

  • 一般来说,拥有 100 列应该不是一个好主意,这通常意味着您的设计中有些东西
  • 是的,不完全是 100,我还有其他带有包含大文本的文本字段的列。但我想知道有没有办法获取我需要的列数据并且还能够调用函数

标签: django django-orm


【解决方案1】:

从上面的查询集中我得到了值,现在我想在对象上调用get_total 函数。我没有找到调用该函数的方法。

好吧,你获得了一个QuerySet(在那个时候没有被评估),所以一个Revenues 的集合。您不能直接调用该集合上的函数。但是您可以通过查询集迭代,并在个别对象上调用该函数。例如,我们可以列出一个列表:

[<b>r.get_total()</b> for r in Revenue.objects.filter(from_a__gt = 10)]

有没有办法只使用值来检索我需要的数据,并且还可以调用这些对象的member_functions

是的,您可以在查询中使用.only(..) 元素来限制加载的列数:

[r.get_total() for r in Revenue.objects.filter(from_a__gt = 10)<b>.only('from_a', 'from_b')</b>]

这将构造Revenue 对象,但我们只会加载指定的列。在这种情况下,我们将只加载from_afrom_b,如果您以后需要其他 字段,这些字段将与额外 查询一起加载。

如果member_functions 中的逻辑很简单,您最好使用注解:这些注解会在数据库中进行处理,从而允许过滤。然而,这并不总是可能的:Python 允许计算非常复杂的东西,这会导致巨大的等效 SQL 表达式。此外,大多数数据库不允许联系 Web 服务和文件系统,因此某些功能根本无法在注释中翻译。

【讨论】:

    【解决方案2】:

    您可以在查询中使用F expression,而不是在模型级别执行此操作:

    from django.db.models import F
    
    Revenue.objects.filter(from_a__gt = 10).annotate(
        get_total=F('from_a') + F('from_b')
    ).values('from_a', 'from_b', 'get_total')
    

    【讨论】:

      【解决方案3】:

      取决于你想做什么...如果你想get_total显示为字段,你可以将此方法设为一个属性方法,他将是计算字段,所以它不会保留在数据库中

      属性方法

      @property
      def get_total(self):
          return self.from_a + self.from_b
      
      Revenue.objects.filter(from_a__gt = 10).values('from_a', 'from_b', 'get_total')
      

      https://docs.djangoproject.com/en/2.0/topics/db/models/#model-methods

      你可以像普通的类方法一样调用它,所以当你得到模型实例时你可以调用它

      revenues = Revenue.objects.filter(from_a__gt = 10).values('from_a', 'from_b')
      for revenue in revenues:
          print(revenue.get_total)
      
      # OR
      [r.get_total for r in Revenue.objects.filter(from_a__gt = 10)] # Like Wilem Van said
      

      静态方法

      将它用作静态方法(这种方式不是最适合您的需要,但很高兴知道),您将将此方法与类绑定,因此您不需要一个对象实例来管理它,只需要类引用 类收入(...): ...

          @staticmethod
          def get_total(valueA, valueB):
              return valueA + valueB
      

      这样称呼 Revenue.get_total(5, 10)

      https://www.programiz.com/python-programming/methods/built-in/staticmethod

      Obs.:很奇怪,在 django 文档中没有很好地参考 staticmethod

      【讨论】:

      • 参考您的第一个示例,模型实例方法,即“get_total”如何在 Queryset 的 .values() 方法中工作?
      • 我意识到我在那里写了一些错误,所以现在更新了,该方法将在你的类中作为常规字段处理,所以不持久化是在你实例化它时计算的,所以你可以使用 values() 并定义要在查询集中显示的列,例如 (class attrA, attrB, @property attrC (return attrA+attrC) MyClass.objects.all().values('attrA', 'attrB' , attrC')
      猜你喜欢
      • 2016-11-10
      • 2012-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-11
      • 1970-01-01
      • 2011-03-10
      相关资源
      最近更新 更多