<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Kolios &#187; django</title>
	<atom:link href="http://www.kolios.dk/category/tech/django/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.kolios.dk</link>
	<description></description>
	<lastBuildDate>Tue, 31 Aug 2010 11:38:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>How to migrate django models with South</title>
		<link>http://www.kolios.dk/2010/02/12/how-to-migrate-django-models-with-south/</link>
		<comments>http://www.kolios.dk/2010/02/12/how-to-migrate-django-models-with-south/#comments</comments>
		<pubDate>Fri, 12 Feb 2010 09:22:22 +0000</pubDate>
		<dc:creator>sebastien</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[django]]></category>

		<guid isPermaLink="false">http://www.kolios.dk/?p=524</guid>
		<description><![CDATA[<img src="http://www.kolios.dk/icons/coding-48x48.png" width="48" height="48" alt="" title="Coding" /><img src="http://www.kolios.dk/icons/django-48x48.png" width="48" height="48" alt="" title="django" /><br/>Hi django fridayers ! Today on python friday, we will discuss the model and data migration of django. Many of you are probably developing the web app in python and are absolutely amazed about how easy it to create a database schema from your django models. Just run an manage.py syncdb and &#8230;voila ! Your [...]]]></description>
			<content:encoded><![CDATA[<img src="http://www.kolios.dk/icons/coding-48x48.png" width="48" height="48" alt="" title="Coding" /><img src="http://www.kolios.dk/icons/django-48x48.png" width="48" height="48" alt="" title="django" /><br/><p>Hi django fridayers !</p>
<p>Today on python friday, we will discuss the model and data migration of django.</p>
<p>Many of you are probably developing the web app in python and are absolutely amazed about how easy it to create a database schema from your django models. Just run an manage.py syncdb and &#8230;voila ! Your brand new application has all the support needed in the backend database.</p>
<p>But let&#8217;s face it, this is not really practical when it comes to modify an application that is ALREADY online and have data (registered users, stored personal information, &#8230;).</p>
<p><span id="more-524"></span></p>
<h3>The problem</h3>
<p>How can you migrate from one model to another without loosing any data ?</p>
<h3>The solution.</h3>
<p><a title="South migration tool" href="http://south.aeracode.org">South</a></p>
<p>This python package will take care of most of the trouble caused by your model modifications.<br />
With South, you can :</p>
<ul>
<li>Modify the schema of your database according to your model</li>
<li>Migrate your data to make sure that you wont lose any data across the migration</li>
</ul>
<p><!-- more --></p>
<h3>Installing South</h3>
<ul>
<li>download</li>
<li>setup.py install (as root)</li>
<li>edit your settings.py to activate &#8220;south&#8221; in the installed apps</li>
</ul>
<h3>A simple example</h3>
<p>You can now type :</p>
<pre class="brush: bash; gutter: false">$&gt; ./manage syncdb</pre>
<p>to create the good tables in your database. South keep track of every migration in the project database.</p>
<p>Now, let&#8217;s consider that you have a the following model:</p>
<pre class="brush: python">class Customer(models.Model):
    name = models.CharField(max_length= 60)

    def __unicode__(self):
        return self.name</pre>
<p>The first thing you need to do is to initialize south so it can keep track of your<br />
modification of models:</p>
<pre class="brush: bash; gutter: false">$&gt; manage.py startmigration customer initial --initial</pre>
<p>This will create your first migration (initial). The migration will basically creates the tables in your database.<br />
Now, you can apply the migration.</p>
<pre class="brush: bash; gutter: false">$&gt; manage.py migrate</pre>
<p>Now, let&#8217;s assume that you want to change it into:</p>
<pre class="brush: python">class Customer(models.Model):
    name = models.CharField(max_length = 60)
    password = models.CharField('this is a clear text password', max_length=60)</pre>
<p>You have to prepare the migration with the following command:</p>
<pre class="brush: bash; gutter: false">$&gt; ./manage.py startmigration customer add_password --auto</pre>
<p>This creates a migration file that contains your modifications. I let you try to figure out what forward and backward methods are for. Once again, when you think that your migration file is good, you can apply the changes :</p>
<pre class="brush: bash; gutter: false">$&gt; ./manage.py migrate</pre>
<p>At this point, your database is totally synced with your model, so let&#8217;s create some data into it:</p>
<pre class="brush: bash; gutter: false">$&gt; ./manage.py shell
&gt; from customer.models import Customer
&gt; c = Customer()
&gt; c.name="sebastien requiem"
&gt; c.password = "secret"
&gt; c.save()
&gt; Customer.objects.all()
[\]</pre>
<h3>A more complex example with DATA migration</h3>
<p>You now decide to split the field <em>name</em> into <em>firstname</em> and <em>lastname</em>. The natural way would be to delete the field name and create two fields named <em>firstname</em> and <em>lastname</em>. And this is Wrong for many reasons:</p>
<ol>
<li>South will not understand that you want to split the name into two distinct fields</li>
<li>South won&#8217;t be able to migrate your data forward AND backward if you want to roll back</li>
</ol>
<p>The good (and ONLY) way to do it is to so it in three steps:</p>
<ol>
<li>modify your model so you add <em>firstname</em> and <em>lastname</em> fields and migrate the schema</li>
<li>create a migration that migrate your DATA (while name, <em>name</em>, <em>firstname</em> and <em>lastname</em> are all accessible)</li>
<li>delete the <em>name</em> field</li>
</ol>
<p>Now, let&#8217;s assume that you want to change you previous model into the following :</p>
<pre class="brush: python">class Customer(models.Model):
    name = models.CharField(max_length = 60)
    firstname = models.CharField(max_length = 60)
    lastname = models.CharField(max_length = 60)
    password = models.CharField('this is a clear text pasword', length=60)

    def __unicode__(self):
        return self.firstname + ", " + self.lastname</pre>
<h3>Migrating the schema</h3>
<p>Nothing fancy here:</p>
<pre class="brush: bash; gutter: false">$&gt; ./manage.py startmigration customer add_first_last_name --auto
$&gt; ./manage.py migrate</pre>
<h3>Migrate the data</h3>
<pre class="brush: bash; gutter: false">$&gt; ./manage.py startmigration customer first_last_data
now edit the migration file newly created and add the following lines :</pre>
<pre class="brush: python">    def forwards(self, orm):
        for customer in orm.Customer.objects.all():
            try:
                customer.first_name, customer.last_name = adopter.name.split(" ", 1)
            except ValueError:
                customer.first_name, customer.last_name = customer.name, ""
            customer.save()

    def backwards(self, orm):
        for customer in orm.Customer.objects.all():
            customer.name = customer.firstname + " " + customer.lastname
            customer.save()</pre>
<p>As you can see, the variable &#8220;orm&#8221; is in fact the real django ORM. you can use it to write data migration in python with the usual django syntax, which is VERY convenient.</p>
<p>run now you data migration:</p>
<pre class="brush: bash; gutter: false">$&gt; ./manage.py migrate</pre>
<p>A quick django shell will ensure that we have the data present in the database where we expect it to be :</p>
<pre class="brush: bash; gutter: false">$&gt;./manage shell
&gt; from customer.models import Customer
&gt; Customer.objects.all()
[]</pre>
<p>We now just need to delete the remaining an unused field.</p>
<p>Change your model :</p>
<pre class="brush: python">class Customer(models.Model):
    firstname = models.CharField(max_length = 60)
    lastname = models.CharField(max_length = 60)
    password = models.CharField('this is a clear text password', length=60)</pre>
<p>and run a simple migration with &#8211;auto</p>
<pre class="brush: bash">$&gt; ./manage.py startmigration customer remove_name --auto</pre>
<p>and apply</p>
<pre class="brush: bash; gutter: false">$&gt; ./manage.py migrate</pre>
<p>Voila.</p>
<p>References:</p>
<ul>
<li><a title="South migration tool" href="http://south.aeracode.org">The South migration tools</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.kolios.dk/2010/02/12/how-to-migrate-django-models-with-south/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
