Django model method or computation as field in database
Using Django ~ = 1.11 and Python 3.6
I need to store "computed" variables as fields in a Django model database.
Here's the model:
from django.db import models
from datetime import date
class Person(model.Model)
"Last Name"
last_name = models.CharField(max_length=25)
"Birthday"
birth_date = models.DateField()
"City of birth"
city_of_birth = models.CharField(max_length=25)
I am creating a unique id using these fields. In particular, I am concatenating parts of each field into one string variable (details below). I managed to get this to work as a property, but I don't know how to store the calculated field in the database.
"Unique ID"
def get_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
unique_id = property(get_id)
I want to do the same with Age. Here's what I have in mind:
"Age calculated from Birth Date"
def get_age(self):
return int((datetime.date.now() - self.birth_date.days) / 365.25)
age = property(get_age)
Therefore, I would like to store the UniqueID and Age variables in the database as fields in the Person model. What's the best practice for doing this? Do I need to initialize the fields first and then do some kind of update request to them?
Note. As I understand it, the current code using the property works for rendering in the view, but is not stored in the database.
Thank you in advance! Please help me improve what I already have.
UPDATE: Here is the code that worked for me. The problem was that I needed to remove the brackets in the save () section after self.unique_id = self.get_unique_id. It was suggested to remove the age from the database and keep it as property.
class Person(models.Model):
unique_id = models.CharField(max_length=6, blank=True)
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 age(self):
return relativedelta(self.birth_date.days, datetime.date.now()).years
def save(self, *args, **kwarg):
self.unique_id = self.get_unique_id
super(Person, self).save(*args, **kwarg)
def __str__(self):
return self.unique_id
source to share
You must override the method save
to your models Person
and create the field unique_id
and age
in 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)
source to share
The model has a clean
method for this kind of thing:
This method should be used to provide spot checks on the model and to change the attributes of your model. For example, you can use it to automatically provide a value for a field, or for validation that requires access to more than one field.
So, lose the property and add a field named unique_id which should be a CharField. Rename get_id
to clean
and replace the return statement:
self.unique_id = a + b + c
If you are sure this will always generate a unique string, consider making this field the primary key. However, if this model has already been ported, you cannot name it id
, as Django already created the field id
as AutoField
for you, so it will take two migrations for you if you are configured for the name 'id' (which you can pass through later).
source to share