Why does the Django related_model property return a string instead of a model instance?

I have strange behavior, at least for me, it causes me some errors in my project.

I use Django 1.9 and the third-party django package ( django-jet ), which uses the field.related_model property in the Django admin, and sometimes it fails because it expects field.related_model return a model instance, and for some of my models returns the model name.

This property is defined in Django code:

 @cached_property def related_model(self): # Can't cache this property until all the models are loaded. apps.check_models_ready() return self.remote_field.model 

Things I tried:

  • If Django related_model is @property and @cached_property works and returns an instance of the model.
  • If I call field.remote_field.model instead of field.related_model on the line that causes the error, it works and returns an instance of the model.

Please, do you have any ideas? I can make a workaround, but I would like to know why this behavior.

Thanks in advance!

+7
python django django-admin django-jet
source share
1 answer

I think the problem here is because jet is trying to use related_model in the RelatedFieldAjaxListFilter.field_choices() method, and this can be done before all applications are loaded. If I understand correctly, the value of related_model initially a string, which is replaced by a model object during the initialization of the model. If you try to get this value before all applications are loaded, you can get a string or object, depending on the loading order of the models. And, since this is a caching property, getting the string value at this point will result in the string value being cached. See, for example, the comment in django.db.models.options ,

 # The mechanism for getting at the related model is slightly odd - # ideally, we'd just ask for field.related_model. However, related_model # is a cached property, and all the models haven't been loaded yet, so # we need to make sure we don't cache a string reference. 

By making related_name unencrypted property, you avoid this problem.

In the django.contrib.admin.filters.RelatedFieldListFilter code django.contrib.admin.filters.RelatedFieldListFilter they DO NOT use the related_model to get the model object, but instead use the django.contrib.admin.utils.get_model_from_relation() utility function. Probably RelatedFieldAjaxListFilter.field_choices() should do something similar.

+2
source share

All Articles