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

      

+6


source to share


3 answers


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)

      

+11


source


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).

+3


source


@ Josemlp's answer only works if you assign the methods as a function expression - i.e. omit the parentheses, otherwise the functions will already be executed when the class is initialized.

0


source







All Articles