Opened 8 years ago

Closed 4 years ago

#12842 closed Bug (fixed)

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
Cc: bnomis@… Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: 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 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:

  1. only register the model if it is actually installed and the table exists in the db
  2. if not installed issue a debug log message
  3. 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, 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.



Attachments (1) (8.5 KB) - added by Simon Blanchard 8 years ago.
test project demonstrating issue of assumption of existence

Download all attachments as: .zip

Change History (10)

Changed 8 years ago by Simon Blanchard

Attachment: added

test project demonstrating issue of assumption of existence

comment:1 Changed 8 years ago by Simon Blanchard

Cc: bnomis@… added

comment:2 Changed 8 years ago by Russell Keith-Magee

Triage Stage: UnreviewedAccepted

The non-existence of tables will always be a problem - Django doesn't force you to run syncdb, so it would be possible to get the errors you describe even if AppB *was* in INSTALLED_APPS.

However, that said, cases where it can be predicted that syncdb won't work should be caught. The last suggestion (that register_models should raise an error if the app isn't mentioned in INSTALLED_APPS) sounds like a plausible solution to me.

comment:3 Changed 8 years ago by niall

Owner: changed from nobody to niall
Status: newassigned

I have a patch that adds a test for app_label or "django.contrib." + app_label being in INSTALLED_APPS but it is causing problems with the other tests (the "apps" the models belong to aren't in the settings). Is there a better way to test for this?

comment:4 Changed 7 years ago by Luke Plant

Type: Bug

comment:5 Changed 7 years ago by Luke Plant

Severity: Normal

comment:6 Changed 6 years ago by Aymeric Augustin

UI/UX: unset

Change UI/UX from NULL to False.

comment:7 Changed 6 years ago by Aymeric Augustin

Easy pickings: unset

Change Easy pickings from NULL to False.

comment:8 Changed 5 years ago by Aymeric Augustin

Component: Core (Other)Database layer (models, ORM)

comment:9 Changed 4 years ago by Aymeric Augustin

Resolution: fixed
Status: assignedclosed

After the app loading refactor, you aren't allowed to import models that aren't in an installed application.

Note: See TracTickets for help on using tickets.
Back to Top