Opened 15 years ago

Closed 11 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: dev
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

Description

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:

  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, 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.

Thanks

Simon

Attachments (1)

test_app_install.zip (8.5 KB ) - added by Simon Blanchard 15 years ago.
test project demonstrating issue of assumption of existence

Download all attachments as: .zip

Change History (10)

by Simon Blanchard, 15 years ago

Attachment: test_app_install.zip added

test project demonstrating issue of assumption of existence

comment:1 by Simon Blanchard, 15 years ago

Cc: bnomis@… added

comment:2 by Russell Keith-Magee, 15 years ago

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 by niall, 14 years ago

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 by Luke Plant, 14 years ago

Type: Bug

comment:5 by Luke Plant, 14 years ago

Severity: Normal

comment:6 by Aymeric Augustin, 13 years ago

UI/UX: unset

Change UI/UX from NULL to False.

comment:7 by Aymeric Augustin, 13 years ago

Easy pickings: unset

Change Easy pickings from NULL to False.

comment:8 by Aymeric Augustin, 12 years ago

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

comment:9 by Aymeric Augustin, 11 years ago

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