Code

Ticket #2225: sql_patch.diff

File sql_patch.diff, 12.3 KB (added by glassresistor, 4 years ago)

Patch which addes a new BaseCommand? based off of AppCommand? called CrossAppCommand? which allows multiple applications transparent access to the models of other app and matches sql printout to syncdb, fix is extended to the other sql management commands

Line 
1Index: django/core/management/commands/sqlall.py
2===================================================================
3--- django/core/management/commands/sqlall.py   (revision 11858)
4+++ django/core/management/commands/sqlall.py   (working copy)
5@@ -1,10 +1,10 @@
6-from django.core.management.base import AppCommand
7+from django.core.management.base import CrossAppCommand
8 
9-class Command(AppCommand):
10+class Command(CrossAppCommand):
11     help = "Prints the CREATE TABLE, custom SQL and CREATE INDEX SQL statements for the given model module name(s)."
12 
13     output_transaction = True
14 
15-    def handle_app(self, app, **options):
16+    def handle_app(self, apps, **options):
17         from django.core.management.sql import sql_all
18-        return u'\n'.join(sql_all(app, self.style)).encode('utf-8')
19+        return u'\n'.join(sql_all(apps, self.style)).encode('utf-8')
20Index: django/core/management/commands/sqlcustom.py
21===================================================================
22--- django/core/management/commands/sqlcustom.py        (revision 11858)
23+++ django/core/management/commands/sqlcustom.py        (working copy)
24@@ -1,10 +1,10 @@
25-from django.core.management.base import AppCommand
26+from django.core.management.base import CrossAppCommand
27 
28-class Command(AppCommand):
29+class Command(CrossAppCommand):
30     help = "Prints the custom table modifying SQL statements for the given app name(s)."
31 
32     output_transaction = True
33 
34-    def handle_app(self, app, **options):
35+    def handle_app(self, apps, **options):
36         from django.core.management.sql import sql_custom
37-        return u'\n'.join(sql_custom(app, self.style)).encode('utf-8')
38+        return u'\n'.join(sql_custom(apps, self.style)).encode('utf-8')
39Index: django/core/management/commands/sql.py
40===================================================================
41--- django/core/management/commands/sql.py      (revision 11858)
42+++ django/core/management/commands/sql.py      (working copy)
43@@ -1,10 +1,10 @@
44-from django.core.management.base import AppCommand
45+from django.core.management.base import CrossAppCommand
46 
47-class Command(AppCommand):
48+class Command(CrossAppCommand):
49     help = "Prints the CREATE TABLE SQL statements for the given app name(s)."
50 
51     output_transaction = True
52 
53-    def handle_app(self, app, **options):
54+    def handle_app(self, apps, **options):
55         from django.core.management.sql import sql_create
56-        return u'\n'.join(sql_create(app, self.style)).encode('utf-8')
57+        return u'\n'.join(sql_create(apps, self.style)).encode('utf-8')
58Index: django/core/management/commands/sqlreset.py
59===================================================================
60--- django/core/management/commands/sqlreset.py (revision 11858)
61+++ django/core/management/commands/sqlreset.py (working copy)
62@@ -1,10 +1,10 @@
63-from django.core.management.base import AppCommand
64+from django.core.management.base import CrossAppCommand
65 
66-class Command(AppCommand):
67+class Command(CrossAppCommand):
68     help = "Prints the DROP TABLE SQL, then the CREATE TABLE SQL, for the given app name(s)."
69 
70     output_transaction = True
71 
72-    def handle_app(self, app, **options):
73+    def handle_app(self, apps, **options):
74         from django.core.management.sql import sql_reset
75-        return u'\n'.join(sql_reset(app, self.style)).encode('utf-8')
76+        return u'\n'.join(sql_reset(apps, self.style)).encode('utf-8')
77Index: django/core/management/commands/sqlclear.py
78===================================================================
79--- django/core/management/commands/sqlclear.py (revision 11858)
80+++ django/core/management/commands/sqlclear.py (working copy)
81@@ -1,10 +1,10 @@
82-from django.core.management.base import AppCommand
83+from django.core.management.base import CrossAppCommand
84 
85-class Command(AppCommand):
86+class Command(CrossAppCommand):
87     help = "Prints the DROP TABLE SQL statements for the given app name(s)."
88 
89     output_transaction = True
90 
91-    def handle_app(self, app, **options):
92+    def handle_app(self, apps, **options):
93         from django.core.management.sql import sql_delete
94-        return u'\n'.join(sql_delete(app, self.style)).encode('utf-8')
95+        return u'\n'.join(sql_delete(apps, self.style)).encode('utf-8')
96Index: django/core/management/commands/sqlindexes.py
97===================================================================
98--- django/core/management/commands/sqlindexes.py       (revision 11858)
99+++ django/core/management/commands/sqlindexes.py       (working copy)
100@@ -1,6 +1,6 @@
101-from django.core.management.base import AppCommand
102+from django.core.management.base import CrossAppCommand
103 
104-class Command(AppCommand):
105+class Command(CrossAppCommand):
106     help = "Prints the CREATE INDEX SQL statements for the given model module name(s)."
107 
108     output_transaction = True
109Index: django/core/management/commands/reset.py
110===================================================================
111--- django/core/management/commands/reset.py    (revision 11858)
112+++ django/core/management/commands/reset.py    (working copy)
113@@ -1,9 +1,9 @@
114-from django.core.management.base import AppCommand, CommandError
115+from django.core.management.base import CrossAppCommand, CommandError
116 from django.core.management.color import no_style
117 from optparse import make_option
118 
119-class Command(AppCommand):
120-    option_list = AppCommand.option_list + (
121+class Command(CrossAppCommand):
122+    option_list = CrossAppCommand.option_list + (
123         make_option('--noinput', action='store_false', dest='interactive', default=True,
124             help='Tells Django to NOT prompt the user for input of any kind.'),
125     )
126@@ -12,16 +12,17 @@
127 
128     output_transaction = True
129 
130-    def handle_app(self, app, **options):
131+    def handle_app(self, apps, **options):
132         from django.db import connection, transaction
133         from django.conf import settings
134         from django.core.management.sql import sql_reset
135+       
136+        for app in apps:
137+            app_name = app.__name__.split('.')[-2]
138 
139-        app_name = app.__name__.split('.')[-2]
140-
141         self.style = no_style()
142 
143-        sql_list = sql_reset(app, self.style)
144+        sql_list = sql_reset(apps, self.style)
145 
146         if options.get('interactive'):
147             confirm = raw_input("""
148Index: django/core/management/base.py
149===================================================================
150--- django/core/management/base.py      (revision 11858)
151+++ django/core/management/base.py      (working copy)
152@@ -297,6 +297,33 @@
153         """
154         raise NotImplementedError()
155 
156+class CrossAppCommand(BaseCommand):
157+    """
158+    Modified version of AppCommand which allows for multiple applications to
159+    see each other models.   
160+    """
161+   
162+    args = '<appname appname ...>'
163+
164+    def handle(self, *app_labels, **options):
165+        from django.db import models
166+        from django.core.management.sql import sql_create
167+        if not app_labels:
168+            raise CommandError('Enter at least one appname.')
169+        try:
170+            app_list = [models.get_app(app_label) for app_label in app_labels]
171+        except (ImproperlyConfigured, ImportError), e:
172+            raise CommandError("%s. Are you sure your INSTALLED_APPS setting is correct?" % e)
173+        return self.handle_app(app_list, **options)
174+
175+    def handle_app(self, apps, **options):   
176+        """
177+        Perform the command's actions for ``apps``, which will be the
178+        Python module corresponding to an application name given on
179+        the command line.
180+        """
181+        raise NotImplementedError()
182+   
183 class LabelCommand(BaseCommand):
184     """
185     A management command which takes one or more arbitrary arguments
186Index: django/core/management/sql.py
187===================================================================
188--- django/core/management/sql.py       (revision 11858)
189+++ django/core/management/sql.py       (working copy)
190@@ -7,7 +7,7 @@
191 except NameError:
192     from sets import Set as set   # Python 2.3 fallback
193 
194-def sql_create(app, style):
195+def sql_create(apps, style):
196     "Returns a list of the CREATE TABLE SQL statements for the given app."
197     from django.db import connection, models
198     from django.conf import settings
199@@ -23,7 +23,13 @@
200     # We trim models from the current app so that the sqlreset command does not
201     # generate invalid SQL (leaving models out of known_models is harmless, so
202     # we can be conservative).
203-    app_models = models.get_models(app, include_auto_created=True)
204+    if isinstance(apps, list):
205+        app_models=[]
206+        for app in apps:
207+             for mod in models.get_models(app, include_auto_created=True):
208+                app_models.append(mod)
209+    else:
210+        app_models = models.get_models(apps, include_auto_created=True)
211     final_output = []
212     tables = connection.introspection.table_names()
213     known_models = set([model for model in connection.introspection.installed_models(tables) if model not in app_models])
214@@ -54,7 +60,7 @@
215 
216     return final_output
217 
218-def sql_delete(app, style):
219+def sql_delete(apps, style):
220     "Returns a list of the DROP TABLE SQL statements for the given app."
221     from django.db import connection, models
222     from django.db.backends.util import truncate_name
223@@ -76,22 +82,24 @@
224 
225     # Output DROP TABLE statements for standard application tables.
226     to_delete = set()
227-
228+    if not isinstance(apps, list):
229+        apps=[apps]
230     references_to_delete = {}
231-    app_models = models.get_models(app, include_auto_created=True)
232-    for model in app_models:
233-        if cursor and connection.introspection.table_name_converter(model._meta.db_table) in table_names:
234-            # The table exists, so it needs to be dropped
235-            opts = model._meta
236-            for f in opts.local_fields:
237-                if f.rel and f.rel.to not in to_delete:
238-                    references_to_delete.setdefault(f.rel.to, []).append( (model, f) )
239+    for app in apps:
240+        app_models = models.get_models(app, include_auto_created=True)
241+        for model in app_models:
242+            if cursor and connection.introspection.table_name_converter(model._meta.db_table) in table_names:
243+                # The table exists, so it needs to be dropped
244+                opts = model._meta
245+                for f in opts.local_fields:
246+                    if f.rel and f.rel.to not in to_delete:
247+                        references_to_delete.setdefault(f.rel.to, []).append( (model, f) )
248 
249-            to_delete.add(model)
250+                to_delete.add(model)
251 
252-    for model in app_models:
253-        if connection.introspection.table_name_converter(model._meta.db_table) in table_names:
254-            output.extend(connection.creation.sql_destroy_model(model, references_to_delete, style))
255+        for model in app_models:
256+            if connection.introspection.table_name_converter(model._meta.db_table) in table_names:
257+                output.extend(connection.creation.sql_destroy_model(model, references_to_delete, style))
258 
259     # Close database connection explicitly, in case this output is being piped
260     # directly into a database client, to avoid locking issues.
261@@ -120,25 +128,28 @@
262     statements = connection.ops.sql_flush(style, tables, connection.introspection.sequence_list())
263     return statements
264 
265-def sql_custom(app, style):
266+def sql_custom(apps, style):
267     "Returns a list of the custom table modifying SQL statements for the given app."
268     from django.db.models import get_models
269     output = []
270-
271-    app_models = get_models(app)
272-    app_dir = os.path.normpath(os.path.join(os.path.dirname(app.__file__), 'sql'))
273-
274-    for model in app_models:
275-        output.extend(custom_sql_for_model(model, style))
276-
277+    app_models = []
278+    if not isinstance(apps, list):
279+        apps=[apps]
280+    for app in apps:
281+        app_dir = os.path.normpath(os.path.join(os.path.dirname(app.__file__), 'sql'))
282+        for model in get_models(app):
283+            output.extend(custom_sql_for_model(model, style))
284     return output
285 
286-def sql_indexes(app, style):
287+def sql_indexes(apps, style):
288     "Returns a list of the CREATE INDEX SQL statements for all models in the given app."
289     from django.db import connection, models
290     output = []
291-    for model in models.get_models(app):
292-        output.extend(connection.creation.sql_indexes_for_model(model, style))
293+    if not isinstance(apps, list):
294+        apps=[apps]
295+    for app in apps:
296+        for model in models.get_models(app):
297+            output.extend(connection.creation.sql_indexes_for_model(model, style))
298     return output
299 
300 def sql_all(app, style):