How to add a calculated field to a Django model
Ok... Daniel Roseman's answer seemed like it should have worked. As is always the case, you find what you're 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:
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)
Django Model Method or Calculation as Field in Database
You have to override the save
method of yout Model Person
and create unique_id
and age
field in the Model.
from dateutil.relativedelta import relativedelta
from datetime import datetime
class Person(model.Model)
unique_id = models.CharField(max_length=25)
age = models.IntegerField()
last_name = models.CharField(max_length=25)
birth_date = models.DateField()
city_of_birth = models.CharField(max_length=25)
@property
def get_unique_id(self):
a = self.last_name[:2].upper() #First 2 letters of last name
b = self.birth_date.strftime('%d') #Day of the month as string
c = self.city_of_birth[:2].upper() #First 2 letters of city
return a + b + c
@property
def get_age(self):
return relativedelta(self.birth_date.days, datetime.date.now()).years
def save(self, *args, **kwargs):
self.unique_id = self.get_unique_id
self.age = self.get_age
super(Person, self).save(*args, **kwargs)
UPDATE: Previously the self.get_unique_id
and self.get_age
were being called with '()' which is not required for class properties.
Derived (Calculated) Field From Another Model
You can use @property
decorator for that, to give you an example:
class Salary(models.Model):
person_id = models.ForeignKey(
Person,
on_delete=models.CASCADE,
)
@property
def name(self):
return self.person_id.name if self.person_id else None
@property
def income_in_euro(self):
if not self.person_id:
return
return Jobs.objects.filter(person_id_id=self.person_id_id).first(). job_income_in_usd * 0.89
btw i do not think its a good idea naming your ForeignKey
s with _id
at the end.
Django Model field calculated from other fields
Figured it out (w the help of AbhiP!) Python int
typecasting was the main culprit. Stupid problem to have!
Below is what worked, and allowed me to not save the calculated field (but display it and make it act like a field in the model):
@property
def yield_num(self):
if self.starts > 0:
#needed the float() to cast it out of an int
return self.finishes / float(self.starts)
else:
return 0
How to add a calculated field to a django admin inline
I wound up having to use a custom ModelForm in the inline. I did it like this:
admin.py:
class MyMembershipInlineForm(forms.ModelForm):
class Meta:
model = MyUser.groups.through
fields = ("group", )
readonly_fields = (
"timestamp",
"size",
)
size = forms.IntegerField(disabled=True)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
my_membership = self.instance
self.initial = {
"size": my_membership.group.size if my_membership.pk else None
}
class MyMembershipInline(admin.TabularInline):
model = MyUser.groups.through
fields = (
"group",
"timestamp",
"size",
)
form = MyMembershipInlineForm
@admin.register(MyUser):
class MyUserAdmin(admin.ModelAdmin)
fields = ("user_name",)
inlines = (MyMembershipInline,)
How do I easily create a calculated field in a Django model?
I think the easiest way is to override the save
method. I don't see any reason why it should save to the database twice.
class SoftwareHelp(Help):
about_software = models.ForeignKey('Software')
def save(self, *args, **kwargs):
self.about_software = 'Help for %s' % self.title
return super(SoftwareHelp, self).save(*args, **kwargs)
How to add a calculated field to a django query expression
I was able to solve my problem using Django's db function Extract (https://docs.djangoproject.com/en/3.1/ref/models/database-functions/#extract)
My DocumentCommentManager:
from django.db.models.functions import Extract
class DocumentCommentManager(models.Manager):
def get_queryset(self):
return super(DocumentCommentManager, self).get_queryset().annotate(created_year=Extract("created","year"))
This solves my original problem of adding a calculated datetime field to the model queries.
I still have not found a general way to add a calculated field to a model query using Q expressions. If you can share any examples, that would be great!
Related Topics
Python - Using Pandas Structures with Large CSV(Iterate and Chunksize)
How to Use Pip to Install a Package from a Private Github Repository
What Limitations Have Closures in Python Compared to Language X Closures
Type Hint for a Function That Returns Only a Specific Set of Values
Python Multiprocessing: Handling Child Errors in Parent
How to Implement _Getattribute_ Without an Infinite Recursion Error
Remove Namespace and Prefix from Xml in Python Using Lxml
Testing Floating Point Equality
Sqlite Insert Query Not Working with Python
How to Select All Columns Whose Names Start with X in a Pandas Dataframe
What Exactly Is Contained Within a Obj._Closure_
Subprocess: Deleting Child Processes in Windows
Using Multipartposthandler to Post Form-Data with Python
Generating Random Dates Within a Given Range in Pandas
How to Set Env Variable in Jupyter Notebook
How to Dump a Dict to a JSON File