Opened 9 years ago

Closed 7 years ago

#2453 closed enhancement (wontfix)

[patch] Define order in which "initial sql data" files are processed

Reported by: Pawel J. Sawicki (http://pjs.name) Owned by: nobody
Component: Core (Other) Version: master
Severity: minor Keywords:
Cc: sam@… Triage Stage: Design decision needed
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

Since, according to http://www.djangoproject.com/documentation/model_api/#providing-initial-sql-data, there was no way to ensure an order in which multiple "initial sql data" files were processed during e.g. "manage.py syncdb" I've prepared the following patch. I hope it may be useful.

$ svn diff

Index: db/models/options.py
===================================================================
--- db/models/options.py	(revision 3496)
+++ db/models/options.py	(working copy)
@@ -13,7 +13,7 @@
 
 DEFAULT_NAMES = ('verbose_name', 'db_table', 'ordering',
                  'unique_together', 'permissions', 'get_latest_by',
-                 'order_with_respect_to', 'app_label')
+                 'order_with_respect_to', 'app_label', 'sql_initialization_order')
 
 class Options(object):
     def __init__(self, meta):
@@ -41,6 +41,7 @@
         self.object_name = cls.__name__
         self.module_name = self.object_name.lower()
         self.verbose_name = get_verbose_name(self.object_name)
+        self.sql_initialization_order = 0
         # Next, apply any overridden values from 'class Meta'.
         if self.meta:
             meta_attrs = self.meta.__dict__
Index: core/management.py
===================================================================
--- core/management.py	(revision 3496)
+++ core/management.py	(working copy)
@@ -492,21 +492,40 @@
 
         # Install initial data for the app (but only if this is a model we've
         # just created)
+        sql_initial_data = {}
         for model in models.get_models(app):
             if model in created_models:
                 initial_sql = get_sql_initial_data_for_model(model)
                 if initial_sql:
-                    print "Installing initial data for %s model" % model._meta.object_name
+                    # Get the order in which the model should be initialized.
+                    sql_initialization_order = model._meta.sql_initialization_order
                     try:
-                        for sql in initial_sql:
-                            cursor.execute(sql)
-                    except Exception, e:
-                        sys.stderr.write("Failed to install initial SQL data for %s model: %s" % \
-                                            (model._meta.object_name, e))
-                        transaction.rollback_unless_managed()
-                    else:
-                        transaction.commit_unless_managed()
+                        sql_initial_data[sql_initialization_order].append(model)
+                    except KeyError:
+                        sql_initial_data[sql_initialization_order] = [model, ]
 
+        # Once we have the initial sql data together with its respective
+        # weights try to install it in an appropriate order.
+        sql_initial_data_keys = sql_initial_data.keys()
+        sql_initial_data_keys.sort()
+        for sql_initialization_order in sql_initial_data_keys:
+            while len(sql_initial_data[sql_initialization_order]):
+                model = sql_initial_data[sql_initialization_order].pop()
+                
+                print "Installing initial data for %s model" % model._meta.object_name
+
+                initial_sql = get_sql_initial_data_for_model(model)
+
+                try:
+                    for sql in initial_sql:
+                        cursor.execute(sql)
+                except Exception, e:
+                    sys.stderr.write("Failed to install initial SQL data for %s model: %s" % \
+                                        (model._meta.object_name, e))
+                    transaction.rollback_unless_managed()
+                else:
+                    transaction.commit_unless_managed()
+
 syncdb.args = ''
 
 def get_admin_index(app):

If you want to influence the order in which files with initial sql data are processed you have to place an attribute called "sql_initialization_order" inside the "Meta" class of a specific model class. The smaller the number, the earlier the file associated with this model will be processed.

This way, if you have multiple models that depend one on another, you may use separate sql initialization files, without the risk of breaking constraints.

Change History (4)

comment:1 Changed 8 years ago by adrian

  • Summary changed from [PATCH] Define order in which "initial sql data" files are processed. to [patch] Define order in which "initial sql data" files are processed

comment:2 Changed 8 years ago by Simon G. <dev@…>

  • Triage Stage changed from Unreviewed to Design decision needed

comment:3 Changed 8 years ago by anonymous

  • Cc sam@… added

comment:4 Changed 7 years ago by jacob

  • Resolution set to wontfix
  • Status changed from new to closed

I don't particularly like this approach, but there is indeed a value in getting particular SQL run absolutely first or absolutely last. Probably the best way to do this is with some extra params on the post_syncdb hook -- see #6066.

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