Opened 13 years ago

Closed 13 years ago

#2028 closed defect (fixed)

Since models do not maintain order , Sqlite code breaks on ForeignKeys

Reported by: ant9000@… Owned by: Adrian Holovaty
Component: Core (Other) Version: master
Severity: normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


I've tried to generate a correct sqlite script for the below:

from django.db import models
class Device(models.Model):
class Module(models.Model):
class Die(models.Model):
class Wafer(models.Model):
    die_type = models.ForeignKey(Die)
class Padpattern(models.Model):
class Probecard(models.Model):

and it won't work even if Die is defined before Wafer, since the models get reordered.

Here is a quick and dirty patch to django.db.models.loading that makes it work correctly:

---	2006-05-29 09:59:52.078390200 +0200
+++	2006-05-29 10:21:42.070052200 +0200
@@ -7,7 +7,10 @@
 _app_list = None # Cache of installed apps.
 _app_models = {} # Dictionary of models against app label
-                 # Each value is a dictionary of model name: model class
+                 # Each value is a dictionary with keys 'list', 'dict'
+		  # used to keep track of model name: model class in a sorted fashion
+		  # - 'list' is a sorted list of the models
+		  # - 'dict' associates the model names with their index in 'list'
 def get_apps():
     "Returns a list of all installed modules that contain models."
@@ -42,7 +45,9 @@
     app_list = get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
     if app_mod:
-        return _app_models.get(app_mod.__name__.split('.')[-2], {}).values()
+        model_entry = _app_models.get(app_mod.__name__.split('.')[-2], {})
+	 model_list  = model_entry.setdefault('list',[])
+	 return model_list
         model_list = []
         for app_mod in app_list:
@@ -56,13 +61,16 @@
     get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
-        model_dict = _app_models[app_label]
+        model_entry = _app_models[app_label]
     except KeyError:
         return None
-        return model_dict[model_name.lower()]
-    except KeyError:
+	 model_dict = model_entry['dict']
+	 model_idx  = model_dict[model_name.lower()]
+	 model_list = model_entry['list']
+        return model_list[model_idx]
+    except KeyError, IndexError:
         return None
 def register_models(app_label, *models):
@@ -73,5 +81,8 @@
         # Store as 'name: model' pair in a dictionary
         # in the _app_models dictionary
         model_name = model._meta.object_name.lower()
-        model_dict = _app_models.setdefault(app_label, {})
-        model_dict[model_name] = model
+        model_entry = _app_models.setdefault(app_label, {})
+	 model_list = model_entry.setdefault('list',[])
+	 model_dict = model_entry.setdefault('dict',{})
+	 model_list.append(model)
+	 model_dict[model_name] = len(model_list)-1

It would probably make sense to implement this hack in a SortedDict class, and use it as the underlying
container for modules.

Your software is great, keep on rocking!


Change History (2)

comment:1 Changed 13 years ago by anonymous

It's worth noting that according to the sqlite docs, foreign key constraints aren't actually enforced. As such, it's likely not worth controlling the order in which tables are created, if it's only for sqlite's benefit.

comment:2 Changed 13 years ago by Malcolm Tredinnick

Resolution: fixed
Status: newclosed

As with #2260, I believe this has been fixed at some point in the interim. Can't give an exact changeset, because there are a few that affected this, but the work is done in django/core/ to save up any references that refer to tables we haven't created yet and output them at the end.

If the problem is not fixed, please reopen (and post the output of " sql ..." for this app).

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