﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
30844	Add after_db_init() hook method to model	Robert Singer	nobody	"I've encountered a need in my personal projects, and when writing [https://github.com/rsinger86/django-lifecycle django-lifecycle], to hook into the moment when a model has been fully initialized from the database. 

Overriding the model's __init__ method does NOT work here because the `select_related` relationships have not yet been added in/cached in the model's FK fields. It would be useful to do things right after the model is fully loaded and initialized from the database. For example, if you have a ""type"" foreign key field, you may want to apply some polymorphic behavior based on the value of that field. Doing this in `__init__` will cause a n+1 query explosion if you load multiple models and iterate over the `QuerySet`.


== Current Problem
This will cause an n+1 issue when iterating a QuerySet:
{{{
class CatMixin(object):
    def greet(self):
         return ""Meow""

class DogMixin(object):
    def greet(self):
         return ""Woof""

class PolymorphicModel(models.Model):
   type = models.ForeignKey(PetType)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
       # another db query is triggered b/c select_related has populated the instance yet
       if self.type.name == 'cat':
           self.__class__ = CatMixin
       else:
           self.__class__ = DogMixin
}}}

== The Fix
Add a call to `obj.post_db_init()` to this line:
https://github.com/django/django/blob/master/django/db/models/query.py#L91

Then this code will eliminate the n+1 problem (assuming `select_related('type')` is used):
{{{
class PolymorphicModel(models.Model):
   type = models.ForeignKey(PetType)

    def post_db_init(self,):
       if type.name == 'cat':
           self.__class__ = CatMixin
       else:
           self.__class__ = DogMixin
}}}

I realize there are other ways to achieve the behavior in this example -- I'm bringing up polymorphism as a general use case. In django-lifecycle, this hook would allow me to track a model instance's initial state across a foreign key relationship without causing users to experience the n+1 problem. 
"	New feature	closed	Database layer (models, ORM)	dev	Normal	wontfix			Unreviewed	0	0	0	0	0	0
