[Django] #35031: overridden **from_db** classmethod doesn't get called if put in the AbstractBaseModel

34 views
Skip to first unread message

Django

unread,
Dec 12, 2023, 9:04:52 AM12/12/23
to django-...@googlegroups.com
#35031: overridden **from_db** classmethod doesn't get called if put in the
AbstractBaseModel
-------------------------------------+-------------------------------------
Reporter: Gaurav | Owner: nobody
Jain |
Type: Bug | Status: new
Component: Database | Version: 4.2
layer (models, ORM) |
Severity: Normal | Keywords:
Triage Stage: | Has patch: 0
Unreviewed |
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
Context:
As described here,
https://docs.djangoproject.com/en/4.2/ref/models/instances/#customizing-
model-loading, I'm overriding **from_db** method to keep track of old and
new values so that I can take necessary actions if the value has changed.
This works fine when I'm overriding this method in individual classes,
however, this method (from_db) doesn't get called when I'm putting this in
the AbstractBaseModel class as described below.


Reproducing steps.

{{{
class AbstractBaseModel(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

class Meta:
abstract = True

@classmethod
def from_db(cls, db, field_names, values):
instance = super().from_db(db, field_names, values)
# save original values, when model is loaded from database
instance._initial_values = dict(zip(field_names, values,
strict=True))
return instance
}}}

To include the above DateTime fields in all models, just extend
it(AbstractBaseModel). Also, override the save method so that we can check
the value before saving the object. e.g. below

{{{
class Country(AbstractBaseModel):
name = models.CharField()

def save(self, *args, **kwargs):
if self.name != self._initial_values["name"]: # This will raise
AttributeError: 'Country' object has no attribute '_initial_values'
# `name` field value has changed/overridden. write
appropriate logic
print(f"New name: {self.name} and Old Name:
{self._initial_values["name"]}")
super().save(*args, **kwargs)
}}}

Above save method will raise the error as the parent class
(AbstractBaseModel) method hasn't been executed so the **_initial_values**
attribute won't be set. However, if you override the **from_db** method
inside the individual model classes, it would work. e.g.

{{{
class Country(AbstractBaseModel):
name = models.CharField()

def save(self, *args, **kwargs):
if self.name != self._initial_values["name"]: # This will work
# `name` field value has changed/overridden. write
appropriate logic
print(f"New name: {self.name} and Old Name:
{self._initial_values["name"]}")
super().save(*args, **kwargs)

@classmethod
def from_db(cls, db, field_names, values):
instance = super().from_db(db, field_names, values)
# save original values, when model is loaded from database
instance._initial_values = dict(zip(field_names, values,
strict=True))
return instance
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/35031>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Dec 13, 2023, 8:34:25 AM12/13/23
to django-...@googlegroups.com
#35031: overridden **from_db** classmethod doesn't get called if put in the
AbstractBaseModel
-------------------------------------+-------------------------------------
Reporter: Gaurav Jain | Owner: nobody
Type: Bug | Status: closed
Component: Database layer | Version: 4.2
(models, ORM) |
Severity: Normal | Resolution: invalid
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0

Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Gaurav Jain):

* status: new => closed
* resolution: => invalid


--
Ticket URL: <https://code.djangoproject.com/ticket/35031#comment:1>

Reply all
Reply to author
Forward
0 new messages