I find that on a few occasions, I've needed to generate extra SQL for
both creation and deletion tasks when I'm executing "manage.py syncdb"
(or sql, or reset, sqlclear, etc., pretty much all of the SQL generation
commands). Currently, if you use only use syncdb for everything, you
can do this in a very limited way. I have a ticket and patch already in
Trac for adding a signal to reset that would work the same way as the
syncdb signal.
But, these cases still wouldn't allow you to just print this
additionally generated SQL, or in any way retrieve and use it from any
of the other commands (sql, sqlclear, etc.). This is sometimes
frustrating, as these additional SQL statements being generated are
dependent on the current state of the model.
I know that "sqlcustom" is available for adding SQL to things, but that
only reads in static files, which is no good if the custom SQL you wish
to generate is specific to the app's models as they stand at the time
they're run.
So, my proposal is this: generate hooks for users. For each of the
get_custom_sql/get_create_sql/etc., add a small portion that checks the
installed apps for their own management.py file and an appropriate
method. For instance, "sqlcustom"'s method could be
"get_custom_sql_for_model_all", denoting that it's run on every model in
every app that is having the current manage.py operation applied to it.
These functions would be expected to return an array of SQL
statements, which could then be fit in with the other generated SQL from
each of the current built in methods.
For clarity, here's an example (with existing statements left in the
method to show where it might be dropped):
(from django/core/management.py)
def get_custom_sql_for_model(model):
...
# Some backends can't execute more than one SQL statement at a time,
# so split into separate statements.
statements = re.compile(r";[ \t]*$", re.M)
# Generate custom SQL from each app's management.py, if it is
designed to
# process all models.
for app_name in settings.INSTALLED_APPS:
try:
app_management = __import__(app_name + '.management', {},
{}, [''])
if 'get_custom_sql_for_model_all' in dir(app_management):
output +=
app_management.get_custom_sql_for_model_all(model)
except ImportError:
pass
# Find custom SQL, if it's available.
...
(an example of <some app>/management.py)
def get_custom_sql_for_model_all(model):
statements = ['SELECT 1', 'SELECT 2']
return statements
This additional block works much in the way that a registered signal
works from syncdb. For every model, all the apps are checked for a
management.py that contains a "get_custom_sql_for_model_all" method. If
the method is found, it's run for the current model. (This also allows
you to have one app that can contain SQL modifiers for all the installed
apps in the system, a HUGE boon to adding functionality project-wide).
Also note that this breaks no existing functionality and creates no
extra dependencies, since anything that is missing is ignored.
How do people feel about this? I will happily generate a patch that
includes all the appropriate methods, not just get_cutom_sql(), but I
want to make sure that this is something that would likely be accepted
into the codebase before doing so.
Thanks,
George