Ticket #2225: sql_patch

File sql_patch, 12.3 KB (added by None, 15 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):
Back to Top