如何将计算字段添加到Django模型

时间:2013-07-16 16:54:36

标签: python django-models django-admin

我有一个简单的Employee模型,其中包含firstnamelastnamemiddlename字段。

在管理员方面,可能在其他地方,我想将其显示为:

lastname, firstname middlename

对我来说,这样做的合理位置是在模型中通过创建一个计算字段:

from django.db import models
from django.contrib import admin

class Employee(models.Model):
    lastname = models.CharField("Last", max_length=64)
    firstname = models.CharField("First", max_length=64)
    middlename = models.CharField("Middle", max_length=64)
    clocknumber = models.CharField(max_length=16)
    name = ''.join(
        [lastname.value_to_string(),
        ',',
         firstname.value_to_string(),
        ' ',
         middlename.value_to_string()])

    class Meta:
        ordering = ['lastname','firstname', 'middlename']

class EmployeeAdmin(admin.ModelAdmin):
    list_display = ('clocknumber','name')
    fieldsets = [("Name", {"fields":(("lastname", "firstname", "middlename"), "clocknumber")}),
        ]

admin.site.register(Employee, EmployeeAdmin)

最终我认为我需要的是将名称字段的值作为字符串。我得到的错误是value_to_string() takes exactly 2 arguments (1 given)。字符串的值需要self, obj。我不确定obj是什么意思。

必须有一个简单的方法来做到这一点,我相信我不是第一个想要这样做的人。

编辑:这是我的代码修改为丹尼尔的答案。我得到的错误是:

django.core.exceptions.ImproperlyConfigured: 
    EmployeeAdmin.list_display[1], 'name' is not a callable or an 
    attribute of 'EmployeeAdmin' of found in the model 'Employee'.


from django.db import models
from django.contrib import admin

class Employee(models.Model):
    lastname = models.CharField("Last", max_length=64)
    firstname = models.CharField("First", max_length=64)
    middlename = models.CharField("Middle", max_length=64)
    clocknumber = models.CharField(max_length=16)

    @property
    def name(self):
        return ''.join(
            [self.lastname,' ,', self.firstname, ' ', self.middlename])

    class Meta:
        ordering = ['lastname','firstname', 'middlename']

class EmployeeAdmin(admin.ModelAdmin):
    list_display = ('clocknumber','name')
    fieldsets = [("Name", {"fields":(("lastname", "firstname", "middlename"), "clocknumber")}),
]

admin.site.register(Employee, EmployeeAdmin)

5 个答案:

答案 0 :(得分:62)

这不是你作为一个领域所做的事情。即使该语法有效,它也只会在定义类时给出值,而不是在您访问它时。您应该将此作为一种方法,并且可以使用@property装饰器使其看起来像普通属性。

@property
def name(self):
    return ''.join(
        [self.lastname,' ,', self.firstname, ' ', self.middlename])

self.lastname等仅显示为其值,因此无需调用任何其他方法来转换它们。

答案 1 :(得分:36)

好的......丹尼尔罗斯曼的回答似乎应该有效。与往常一样,您在发布问题之后找到了您正在寻找的内容。

从开箱即用的django 1.5 docs I found this example开始。感谢大家的帮助。

以下是有效的代码:

from django.db import models
from django.contrib import admin

class Employee(models.Model):
    lastname = models.CharField("Last", max_length=64)
    firstname = models.CharField("First", max_length=64)
    middlename = models.CharField("Middle", max_length=64)
    clocknumber = models.CharField(max_length=16)

    def _get_full_name(self):
        "Returns the person's full name."
        return '%s, %s %s' % (self.lastname, self.firstname, self.middlename)
    full_name = property(_get_full_name)


    class Meta:
        ordering = ['lastname','firstname', 'middlename']

class EmployeeAdmin(admin.ModelAdmin):
    list_display = ('clocknumber','full_name')
    fieldsets = [("Name", {"fields":(("lastname", "firstname", "middlename"), "clocknumber")}),
]

admin.site.register(Employee, EmployeeAdmin)

答案 2 :(得分:18)

Daniel Roseman的解决方案使计算字段成为Model的属性,但does not make it accessible via QuerySet methods(例如。all().values())。这是因为QuerySet方法call the database directly,绕过了django Model

由于QuerySets直接访问数据库,因此解决方案是通过附加计算字段来覆盖Manager的{​​{1}}方法。计算字段使用.get_queryset()创建。最后,您将.annotate()中的objects经理设置为新的Model

以下是一些证明这一点的代码:

  

models.py

Manager

现在,您可以致电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() .values()并访问.all()中声明的新计算的link属性。

也可以在Manager中使用other functions,例如.annotate()

我认为该属性仍然无法在F()中使用。我相信你可以在这里添加它,但我还没有探究过 - 任何编辑/评论都会有所帮助。

答案 3 :(得分:4)

我最近在一个图书馆工作,可以解决你很容易解决的问题。

https://github.com/brechin/django-computed-property

安装它,添加到INSTALLED_APPS然后

class Employee(models.Model):
    ...
    name = computed_property.ComputedCharField(max_length=3 * 64, compute_from='full_name')

    @property
    def full_name(self):
        return '{LAST}, {FIRST} {MIDDLE}'.format(LAST=self.lastname, FIRST=self.firstname, MIDDLE=self.middlename')

答案 4 :(得分:1)

在这种情况下,如果您只是要在管理网站中使用该字段表示此类问题,最好考虑覆盖 str ()或 unicode ( )django文档here中提到的类的方法:

class Employee(models.Model):
    # fields definitions
    def __str__(self):
        return self.lastname + ' ,' + self.firstname + ' ' + self.middlename