Django

Code

Ticket #2453 (closed: wontfix)

Opened 2 years ago

Last modified 1 year ago

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

Reported by: Pawel J. Sawicki (http://pjs.name) Assigned to: nobody
Milestone: Component: Core framework
Version: SVN Keywords:
Cc: sam@robots.org.uk Triage Stage: Design decision needed
Has patch: 1 Needs documentation: 0
Needs tests: 0 Patch needs improvement: 0

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.

Attachments

Change History

11/26/06 18:10:09 changed 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.

02/17/07 04:14:08 changed by Simon G. <dev@simon.net.nz>

  • stage changed from Unreviewed to Design decision needed.

10/19/07 05:29:38 changed by anonymous

  • cc set to sam@robots.org.uk.

11/30/07 15:56:23 changed by jacob

  • status changed from new to closed.
  • resolution set to wontfix.

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.


Add/Change #2453 ([patch] Define order in which "initial sql data" files are processed)




Change Properties
Action