Importing a non-installed app assumes the non-installed DB table exists
|Reported by:||Simon Blanchard||Owned by:||niall|
|Component:||Database layer (models, ORM)||Version:||master|
|Severity:||Normal||Keywords:||installed, model, relation|
|Has patch:||no||Needs documentation:||no|
|Needs tests:||no||Patch needs improvement:||no|
The project example attached demonstrates the problem with the assumption built into Django that if a model is "seen" it is installed and its database table exists. This is particularly a problem with model inheritance. In this example AppB inherits from AppA but AppB is not installed. AppC imports AppB causing AppB to be "seen" and added to the list of installed apps together with the assumption that its table exists in the database. So when an AppA object is deleted Django also issues SQL to delete from the AppB table - which throws an error because it does not exist.
See the test.py file which gives the following error:
django.db.utils.DatabaseError: relation "AppB_appb" does not exist LINE 1: ...ppB_appb"."appa_ptr_id", "AppB_appb"."nameb" FROM "AppB_appb...
The ModelBase meta class calls register_models when the class is created. I suggest that register_models should do one of the following:
- only register the model if it is actually installed and the table exists in the db
- if not installed issue a debug log message
- if not installed throw an exception
Number 1 with number 2 is my preference.
If you have a library with lots of models and lots of inheritance you probably do not want to install all the models for all projects. But some of the apps which are installed might reference a non-installed app merely by, quite legitimately, importing its class.
It's possible to work around this issue by checking all reference to models are installed before using them. See AppC.models, test.py and the APPB_IS_INSTALLED setting.
I guess, fundamentally, it's a question of philosophy: is it Django's philosophy that if a Model is seen, it is installed and exists in the database? The current behaviour. If so, this and the consequence of it should be stated in large letters in the documentation.
I suggest that if the current behaviour is as intended then a check should be put in to register_models() (if DEBUG is set?) to catch references to non-installed models and to log an error message that your site is probably going to crash soon. This, at least, would make the source of the error more obvious.