<p>Daniel Roseman的解决方案使计算字段成为一个<code>Model</code>的属性,然而它是<a href="https://stackoverflow.com/questions/11465293/create-a-field-which-value-is-a-calculation-of-other-fields-values#comment34642730_11465349">does not make it accessible via QuerySet methods</a>(例如<code>all()</code>,<code>.values()</code>)。这是因为QuerySet方法<a href="https://stackoverflow.com/a/8623663/3247120">call the database directly</a>,绕过django <code>Model</code>。</p>
<p>由于queryset直接访问数据库,解决方案是通过附加计算字段来重写<code>Manager</code>的<code>.get_queryset()</code>方法。使用<code>.annotate()</code>创建计算字段。最后,将<code>Model</code>中的<code>objects</code>管理器设置为新的<code>Manager</code>。</p>
<p>下面是一些代码来演示这一点:</p>
<blockquote>
<p>models.py</p>
</blockquote>
<pre><code>from django.db.models.functions import Value, Concat
from django.db import Model
class InvoiceManager(models.Manager):
"""QuerySet manager for Invoice class to add non-database fields.
A @property in the model cannot be used because QuerySets (eg. return
value from .all()) are directly tied to the database Fields -
this does not include @property attributes."""
def get_queryset(self):
"""Overrides the models.Manager method"""
qs = super(InvoiceManager, self).get_queryset().annotate(link=Concat(Value("<a href='#'>"), 'id', Value('</a>')))
return qs
class Invoice(models.Model):
# fields
# Overridden objects manager
objects = InvoiceManager()
</code></pre>
<p>现在,您可以调用<code>.values()</code>或<code>.all()</code>,并访问在<code>Manager</code>中声明的新计算的<code>link</code>属性。</p>
<p>也可以在<code>.annotate()</code>中使用<a href="https://stackoverflow.com/a/39222984/3247120">other functions</a>,例如<code>F()</code>。</p>
<p>我相信属性在<code>object._meta.get_fields()</code>中仍然不可用。我相信你可以在这里添加它,但我还没有探索如何-任何编辑/评论将是有益的。</p>