Django

Code

Changeset 5780

Show
Ignore:
Timestamp:
07/31/07 11:36:13 (1 year ago)
Author:
danderson
Message:

schema-evolution: updated docs to include more useful "howto" information

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/schema-evolution/docs/schema-evolution.txt

    r5737 r5780  
    1 ===================================== 
    2 Django Schema Evolution Documentation     
    3 ===================================== 
    4  
    5 Schema evolution is the function of updating an existing Django generated 
    6 database schema to a newer/modified version based upon a newer/modified set of 
    7 Django models. 
    8  
    9 This documentation will take you through several common model changes and show 
    10 you how Django's schema evolution handles them. Each example provides the pre  
    11 and post model source code, as well as the SQL output. 
    12  
    13 Adding / Removing Fields 
    14 ------------------------ 
     1= Schema Evolution Documentation = 
     2 
     3== Introduction == 
     4 
     5Schema evolution is the function of updating an existing Django generated database schema to a newer/modified version based upon a newer/modified set of Django models. 
     6 
     7=== Limitations === 
     8 
     9I feel it important to note that is an automated implementation designed to handle schema ''evolution'', not ''revolution''.  No tool, other than storing DBA written SQL scripts and auto-applying them via schema versioning or DB fingerprinting (which is a trivial solution - I have a Java implementation if anyone wants it), can handle the full scope of possible database changes.  Once you accept this fact, the following becomes self-evident: 
     10 
     11 * There is a trade off between ease of use and the scope of coverable problems. 
     12 
     13Combine that with: 
     14 
     15 * The vast majority of database changes are minor, evolutionary tweaks. (*) 
     16 * Very few people are DBAs. 
     17 
     18And I believe the ideal solution is in easing the life of common Django developer, not in appeasing the DBA's or power-developer's desire for an all-in-one-comprehensive solution.  Massive schema changes (w/ data retention) are always going to require someone with database skill, but we can empower the people to do the simple things for themselves. 
     19 
     20(*) By this I mean adding/removing/renaming tables and adding/removing/renaming/changing-attributes-of columns. 
     21 
     22== Downloading / Installing == 
     23 
     24This functionality is not yet in Django/trunk, but in a separate schema-evolution branch.  To download this branch, run the following: 
     25 
     26{{{ 
     27svn co http://code.djangoproject.com/svn/django/schema-evolution/ django_se_src 
     28ln -s `pwd`/django_se_src/django SITE-PACKAGES-DIR/django 
     29}}} 
     30 
     31Or, if you're currently running Django v0.96, run the following: 
     32 
     33{{{ 
     34cd /<path_to_python_dir>/site-packages/django/ 
     35wget http://kered.org/blog/wp-content/uploads/2007/07/django_schema_evolution-v096patch.txt 
     36patch -p1 < django_schema_evolution-v096patch.txt 
     37}}} 
     38 
     39The last command will produce the following output: 
     40 
     41{{{ 
     42patching file core/management.py 
     43patching file db/backends/mysql/base.py 
     44patching file db/backends/mysql/introspection.py 
     45patching file db/backends/postgresql/base.py 
     46patching file db/backends/postgresql/introspection.py 
     47patching file db/backends/sqlite3/base.py 
     48patching file db/backends/sqlite3/introspection.py 
     49patching file db/models/fields/__init__.py 
     50patching file db/models/options.py}}} 
     51}}} 
     52 
     53== How To Use == 
     54 
     55For the most part, schema evolution is designed to be automagic via introspection.  Make changes to your models, run syncdb, and you're done.  But like all schema changes, it's wise to preview what is going to be run.  To do this, run the following: 
     56 
     57{{{ 
     58./manage sqlevolve app_name 
     59}}} 
     60 
     61This will output to the command line the SQL to be run to bring your database schema up to date with your model structure. 
     62 
     63However not everything can be handled through introspection.  A small amount of metadata is used in the cases of model or field renames, so that the introspection code can match up the old field to the new field. (therefore preserving your data) 
     64 
     65For renaming a column, use an "aka" attribute: 
     66 
     67{{{ 
     68    # this field used to be called pub_date 
     69    publish_date = models.DateTimeField('date published', aka='pub_date') 
     70}}} 
     71 
     72If you have renamed this twice and still wish to support migration from both older schemas, "aka"s can be tuples: 
     73 
     74{{{ 
     75    # this field used to be called pub_date 
     76    publish_date = models.DateTimeField('date published', aka=('pub_date','other_old_field_name')) 
     77}}} 
     78 
     79For renaming a model, add an "aka" field to the Meta section: 
     80 
     81{{{ 
     82# the original name for this model was 'Choice' 
     83class Option(models.Model): 
     84    [...] 
     85    class Meta: 
     86        aka = 'Choice' 
     87}}} 
     88 
     89For further examples... 
     90 
     91== Usage Examples == 
     92 
     93The following documentation will take you through several common model changes and show you how Django's schema evolution handles them. Each example provides the pre and post model source code, as well as the SQL output. 
     94 
     95=== Adding / Removing Fields === 
    1596 
    1697Model: version 1 
    1798 
     99{{{ 
    18100    from django.db import models 
    19101     
     
    31113        def __str__(self): 
    32114            return self.choice 
     115}}} 
    33116 
    34117Model: version 2 
    35          
     118 
     119{{{      
    36120    from django.db import models 
    37121     
     
    57141        hasSomething = models.BooleanField() 
    58142        creatorIp = models.IPAddressField() 
     143}}} 
    59144 
    60145Output: v1⇒v2          
    61146 
     147{{{ 
    62148    BEGIN; 
    63149    ALTER TABLE `case01_add_field_poll` ADD COLUMN `pub_date2` datetime NOT NULL; 
     
    66152    ALTER TABLE `case01_add_field_choice` ADD COLUMN `creatorIp` char(15) NOT NULL; 
    67153    COMMIT; 
     154}}} 
    68155 
    69156Output: v2⇒v1          
    70157 
     158{{{ 
    71159    -- warning: as the following may cause data loss, it/they must be run manually 
    72160    -- ALTER TABLE `case01_add_field_poll` DROP COLUMN `pub_date2`; 
     
    74162    -- warning: as the following may cause data loss, it/they must be run manually 
    75163    -- ALTER TABLE `case01_add_field_choice` DROP COLUMN `votes2`; 
    76     -- end warning 
    77164    -- ALTER TABLE `case01_add_field_choice` DROP COLUMN `creatorIp`; 
    78     -- end warning 
    79165    -- ALTER TABLE `case01_add_field_choice` DROP COLUMN `hasSomething`; 
    80166    -- end warning 
    81  
    82 Renaming Fields 
    83 --------------- 
     167}}} 
     168 
     169=== Renaming Fields === 
    84170 
    85171Model: version 1 
    86172 
     173{{{ 
    87174    from django.db import models 
    88175 
     
    103190        def __str__(self): 
    104191            return self.choice 
     192}}} 
    105193 
    106194Model: version 2 
    107195 
     196{{{ 
    108197    from django.db import models 
    109198     
     
    124213        def __str__(self): 
    125214            return self.choice 
     215}}} 
    126216 
    127217Output: v1⇒v2          
    128218 
     219{{{ 
    129220    BEGIN; 
    130221    ALTER TABLE `case02_rename_field_poll` CHANGE COLUMN `pub_date` `published_date` datetime NOT NULL; 
     
    132223    ALTER TABLE `case02_rename_field_choice` CHANGE COLUMN `votes` `number_of_votes` integer NOT NULL; 
    133224    COMMIT; 
    134  
    135 Renaming Models 
    136 --------------- 
     225}}} 
     226 
     227=== Renaming Models === 
    137228 
    138229Model: version 1 
    139230 
     231{{{ 
    140232    from django.db import models 
    141233     
     
    156248        class Meta: 
    157249            aka = ('Choice', 'OtherBadName') 
     250}}} 
    158251 
    159252Model: version 2 
    160253 
     254{{{ 
    161255    from django.db import models 
    162256     
     
    178272        class Meta: 
    179273            aka = ('Choice', 'BadName') 
     274}}} 
    180275     
    181276Output: v1⇒v2          
    182277 
     278{{{ 
    183279    BEGIN; 
    184280    ALTER TABLE `case03_rename_model_choice` RENAME TO `case03_rename_model_option`; 
    185281    ALTER TABLE `case03_rename_model_option` CHANGE COLUMN `number_of_votes` `votes` integer NOT NULL; 
    186282    COMMIT; 
    187  
    188 Changing Flags 
    189 -------------- 
     283}}} 
     284 
     285=== Changing Flags === 
    190286 
    191287Model: version 1 
    192288 
     289{{{ 
    193290    from django.db import models 
    194291     
     
    214311        ) 
    215312        gender = models.CharField(maxlength=1, choices=GENDER_CHOICES) 
     313}}} 
    216314     
    217315Model: version 2 
    218316 
     317{{{ 
    219318    from django.db import models 
    220319     
     
    244343        gender2 = models.CharField(maxlength=1, null=True, unique=True) 
    245344             
     345}}} 
    246346 
    247347Output: v1⇒v2          
    248348 
     349{{{ 
    249350    BEGIN; 
    250351    ALTER TABLE `case04_change_flag_poll` MODIFY COLUMN `question` varchar(100) NOT NULL; 
     
    254355    ALTER TABLE `case04_change_flag_choice` ADD COLUMN `votes2` integer NOT NULL; 
    255356    COMMIT; 
    256  
    257 Conclusion 
    258 ---------- 
     357}}} 
     358 
     359== Conclusion == 
    259360 
    260361That's pretty much it. If you can suggest additional examples or test cases you