| 1 | I have a situation where I want to modify each database table as it is created. The solution I created should work for PostgreSQL or any backend. In this particular case, my project is using a MySQL database, and requires transactions- that is, InnoDB storage. Alas, my hosting service defaults all tables to MyISAM, and I can't change that. |
| 2 | |
| 3 | The usual method is to create a custom sql file "app_model.sql" that alters the table. That gets tedious when one has dozens, or hundreds of models. |
| 4 | |
| 5 | Here's an 80% solution. Add code like the below to your app's {{{ __init__.py }}}: |
| 6 | |
| 7 | |
| 8 | {{{ |
| 9 | # use a consistant MySQL storage type for all apps, all models |
| 10 | |
| 11 | from django.dispatch import dispatcher |
| 12 | from django.db.models import signals |
| 13 | |
| 14 | default_storage = 'InnoDB' |
| 15 | storage = { 'app_model_has_different_storage':'MyISAM'} |
| 16 | skip = set(('app_model_should_go_unchanged',)) |
| 17 | |
| 18 | def modify_MySQL_storage(sender, app, created_models, verbosity, interactive): |
| 19 | from django.db import connection |
| 20 | cursor = connection.cursor() |
| 21 | |
| 22 | for model in created_models: |
| 23 | db_table=model._meta.db_table |
| 24 | if db_table not in skip: |
| 25 | skip.add(db_table) |
| 26 | engine = storage.get(model._meta.db_table,default_storage) |
| 27 | stmt = 'ALTER TABLE %s ENGINE=%s' % (db_table,engine) |
| 28 | if verbosity > 1: print ' ',stmt |
| 29 | cursor.execute(stmt) |
| 30 | |
| 31 | # Modify SQL storage after any app installs |
| 32 | dispatcher.connect(modify_MySQL_storage,signal=signals.post_syncdb) |
| 33 | }}} |
| 34 | |
| 35 | I call this an 80% solution because it won't touch the intermediary M2M tables. For that, we need a signal that fires on the creation of each database table, or lists all tables that were created, which doesn't exist. |
| 36 | |
| 37 | If most tables are InnoDB but you try setting one or a few to MyISAM using {{{storage}}}, MySQL may complain about foreign keys... rather than making that work, I found it simpler to add the table to {{{skip}}} and write out the alter statement the old way, with the raw sql in {{{app/sql/app_model.sql}}}. |
| 38 | |
| 39 | The code could be refined to only alter models in a particular app. |