I have a simple Employee
model that includes firstname
, lastname
and middlename
fields.
On the admin side and likely elsewhere, I would like to display that as:
lastname, firstname middlename
To me the logical place to do this is in the model by creating a calculated field as such:
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)
Ultimately what I think I need is to get the value of the name fields as strings. The error I am getting is value_to_string() takes exactly 2 arguments (1 given)
. Value to string wants self, obj
. I am not sure what obj
means.
There must be an easy way to do this, I am sure I am not the first to want to do this.
Edit: This is my code modified to Daniel's answer. The error I get is:
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)
In this case if you are only going to use the field for representation in admin site and such issues, you might better to consider overriding str() or unicode() method of the class as it is mentioned in django documentation here:
That's not something you do as a field. Even if that syntax worked, it would only give the value when the class was defined, not at the time you access it. You should do this as a method, and you can use the
@property
decorator to make it look like a normal attribute.self.lastname
etc appear as just their values, so no need to call any other method to convert them.Ok... Daniel Roseman's answer seemed like it should have worked. As is always the case, you find what your looking for after you post the question.
From the django 1.5 docs I found this example that worked right out of the box. Thanks to all for your help.
Here is the code that worked:
Daniel Roseman's solution makes a calculated field an attribute of a
Model
, however it does not make it accessible via QuerySet methods (eg. .all()
,.values()
). This is because QuerySet methods call the database directly, circumventing the djangoModel
.Since QuerySets access the database directly, the solution is to override the
Manager
's.get_queryset()
method by appending your calculated field. The calculated field is created using.annotate()
. Finally, you set theobjects
Manager in yourModel
to your newManager
.Here is some code demonstrating this:
Now, you will be able to call
.values()
or.all()
and access the newly calculatedlink
attribute as declared in theManager
.It would have also been possible to use other functions in
.annotate()
, such asF()
.I believe the attribute would still not be available in
object._meta.get_fields()
. I believe you can add it here, but I haven't explored how - any edits/comments would be helpful.I recently worked on a library that may solve the problem you're having quite easily.
https://github.com/brechin/django-computed-property
Install that, add to INSTALLED_APPS and then