Reputation: 380
*****Working with Django 1.11.x and Python 3.6*****
I'm trying to learn how to use the save() method in a Django model (models.py). There are two fields here that I want to become custom, 'calculated' fields (unique_id and age).
First I initiate the field variables, then define methods/properties based on existing fields, then I try to save the method results into the fields that I created.
from django.db import models
from dateutil.relativedelta import relativedelta
from datetime import datetime
class Person(models.Model):
unique_id = models.CharField(max_length=6, primary_key=True)
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, **kwarg):
self.unique_id = self.get_unique_id()
self.age = self.get_age()
super(Person, self).save(*args, **kwarg)
def __str__(self):
return self.unique_id
First, I create 5 fields. 2 of them are placeholders: unique_id and age. Then I define two @property methods and each return a different type of result. The "get_unique_id" function works, but I can't get the result stored in the database. The "get_age" function may or may not be working. I haven't been able to produce it yet.
My primary question is how to correctly use the save() function to override the initial field values (unique_id and age) with my 'calculated field' methods (get_unique_id and get_age).
My primary problem is that when I add a Person (using the Person ModelForm in /Admin), it produces a TypeError: 'str' object is not callable at the line "self.unique_id = self.get_unique_id()". I am currently using the Admin interface to test.
Eventually, I need to learn how to NOT display these 2 fields in the forms, since they will be calculated based on the other fields. I think I may have found documentation on Meta that might help. Also, I want the unique_id field to be the primary key, so I added this option to the initial field.
I have a secondary question (my apologies for being new to Django) about the *args, and **kwargs. Is it okay to leave them there? I'm really unsure about which arguments I need to use, if any, and whether or not it's necessary to include *args and **kwargs in the code.
NOTE: To anyone who helped me yesterday with this app, I really appreciate your help. I consider this to be different than my previous question, although I'm using much of the same code.
Upvotes: 1
Views: 730
Reputation: 78556
Properties are not callable. When you access self.get_unique_id
, Python makes the call to the underlying method decorated by @property
behind the scenes, which in this case returns a string. You don't need to call it again, drop the parens:
def save(self, *args, **kwarg):
self.unique_id = self.get_unique_id
self.age = self.get_age
super(Person, self).save(*args, **kwarg)
OTOH, going by @DanielRoseman's comment, you don't need store the age in the database. Just calculate it when its needed. You could rename get_age
as age
and drop the age
field, so age
becomes a property.
Upvotes: 4