我有一个简单的
Employee
模型,其中包括 firstname
、lastname
和 middlename
字段。
在管理方面以及可能在其他地方,我想将其显示为:
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)
这不是你作为一个领域所做的事情。即使该语法有效,它也只会在定义类时给出值,而不是在访问它时给出值。您应该将其作为一种方法来执行,并且可以使用
@property
装饰器使其看起来像普通属性。
@property
def name(self):
return ''.join(
[self.lastname,' ,', self.firstname, ' ', self.middlename])
self.lastname
等仅显示为它们的值,因此无需调用任何其他方法来转换它们。
Daniel Roseman 的解决方案使计算字段成为
Model
的属性,但是它 无法通过 QuerySet 方法 访问它(例如. .all()
、.values()
)。这是因为 QuerySet 方法直接调用数据库,绕过了 django Model
。
由于 QuerySet 直接访问数据库,解决方案是通过附加计算字段来覆盖
Manager
的 .get_queryset()
方法。计算字段是使用 .annotate()
创建的。最后,您将 objects
中的 Model
管理器设置为新的 Manager
。
这里有一些代码演示了这一点:
模型.py
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
中声明的那样。
也可以在 .annotate()
中使用
其他功能,例如
F()
。
我相信该属性在
object._meta.get_fields()
中仍然不可用。我相信您可以在此处添加它,但我还没有探索如何添加 - 任何编辑/评论都会有帮助。
好吧...丹尼尔·罗斯曼的回答似乎应该有效。与往常一样,您会在发布问题后找到所需内容。
从 Django 1.5 文档 我发现这个示例可以开箱即用。感谢大家的帮助。
这是有效的代码:
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)
我最近开发了一个库,可以很轻松地解决您遇到的问题。
https://github.com/brechin/django-compulated-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')
在这种情况下,如果您只想使用该字段在管理站点中表示和此类问题,您最好考虑重写该类的 str() 或 unicode() 方法,如 django 文档中提到的那样这里:
class Employee(models.Model):
# fields definitions
def __str__(self):
return self.lastname + ' ,' + self.firstname + ' ' + self.middlename
从 Django 5.0 开始,现在可以使用新的 GeneratedField。
对于这个具体问题/情况,如下所示:
from django.db.models import F
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)
full_name= models.GeneratedField(
expression=(F('lastname') + ', ' + F('firstname') + ' ' + F('middlename')),
output_field=models.FloatField,
db_persist=True)
class Meta:
ordering = ['name']
从这里开始,对于几乎所有意图和目的,
full_name
可以像任何其他模型字段一样使用(即排序、管理等)。