{"id":5907,"date":"2018-04-27T17:14:53","date_gmt":"2018-04-27T17:14:53","guid":{"rendered":"https:\/\/blog-stg.cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/"},"modified":"2022-07-01T17:24:15","modified_gmt":"2022-07-01T17:24:15","slug":"keeping-data-integrity-django-migrations","status":"publish","type":"post","link":"https:\/\/blog-stg.cheesecakelabs.com\/br\/keeping-data-integrity-django-migrations\/","title":{"rendered":"Keeping data integrity with Django migrations"},"content":{"rendered":"<p><span style=\"font-weight: 400;\"><a href=\"https:\/\/blog-stg.cheesecakelabs.com\/django-framework-app-development\/\">Django<\/a> built-in migrations were designed as a way of propagating the changes you make on the models to the database. Migrations exist mostly to keep your code in sync with your schema and to provide a good way of versioning it. We just need a couple of commands to get our apps up and running with an updated version of our database, or <\/span><a href=\"https:\/\/blog-stg.cheesecakelabs.com\/really-annoys-django-migrations\/\"><span style=\"font-weight: 400;\">not<\/span><\/a><span style=\"font-weight: 400;\">.<\/span><\/p>\n<p><!--more--><\/p>\n<p><span style=\"font-weight: 400;\">Unfortunately, there are some situations when applying a migration by itself is not enough. What would you do if you needed to add a required field to an existing table? How about changing a many-to-many relationship to just a foreign key without losing pre-existing data? It may be painful and critical to make these changes without the right tool; that&#8217;s why we have <strong>Data Migrations<\/strong>! In this post I&#8217;ll use data migrations to approach these two scenarios.<\/span><\/p>\n<h1><b>First Scenario<\/b><\/h1>\n<p><span style=\"font-weight: 400;\">Let&#8217;s say you have to design a tracking system for a company that sells computers. This system should register the computers bought by each customer. We can migrate the following models:<\/span><\/p>\n<p><a href=\"https:\/\/github.com\/murilocamargos\/data-migrations-blog\/blob\/6c38dde2f15e569dc8d03df3743e7be331b61147\/store\/models.py\"><span style=\"font-weight: 400; font-size: 12px;\">GitHub<\/span><\/a><br \/>\n<!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #fbfbfb; overflow: auto; width: auto; padding: .6em; font-size: .85em; margin-top: -10px;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000; font-weight: bold;\">from<\/span> <span style=\"color: #0000ff; font-weight: bold;\">django.db<\/span> <span style=\"color: #008000; font-weight: bold;\">import<\/span> models\n\n<span style=\"color: #408080; font-style: italic;\"># Create your models here.<\/span>\n<span style=\"color: #008000; font-weight: bold;\">class<\/span> <span style=\"color: #0000ff; font-weight: bold;\">Client<\/span>(models<span style=\"color: #666666;\">.<\/span>Model):\n    name <span style=\"color: #666666;\">=<\/span> models<span style=\"color: #666666;\">.<\/span>CharField(max_length<span style=\"color: #666666;\">=255<\/span>)\n\n<span style=\"color: #008000; font-weight: bold;\">class<\/span> <span style=\"color: #0000ff; font-weight: bold;\">Computer<\/span>(models<span style=\"color: #666666;\">.<\/span>Model):\n    brand <span style=\"color: #666666;\">=<\/span> models<span style=\"color: #666666;\">.<\/span>CharField(max_length<span style=\"color: #666666;\">=255<\/span>)\n    bought_by <span style=\"color: #666666;\">=<\/span> models<span style=\"color: #666666;\">.<\/span>ForeignKey(Client, related_name<span style=\"color: #666666;\">=<\/span><span style=\"color: #ba2121;\">'computers'<\/span>)\n<\/pre>\n<\/div>\n<p><span style=\"font-weight: 400;\">Now, for some reason, we&#8217;ll need to fetch a list with the information of how many computers each customer has bought. Somehow, this is incredibly expensive to compute and your queries would take extra time if you use <\/span><a href=\"https:\/\/docs.djangoproject.com\/en\/1.11\/topics\/db\/aggregation\/\"><span style=\"font-weight: 400;\">annotations<\/span><\/a><span style=\"font-weight: 400;\"> with a Count aggregation. One possible solution would be to add a column on the Customer model to keep track of the amount of computers sold to that specific customer. To keep data integrity, we&#8217;ll make this field required for all new customers.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">To provide the initial data to &nbsp;this new computed required field on your model, you can use a data migration. It basically works by executing a custom function in between schema migrations.<\/span><\/p>\n<p><b>Step 1.<\/b><span style=\"font-weight: 400;\"> First we add the field to our model as a non-required field and run the <\/span><span style=\"font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;\">makemigration<\/span><span style=\"font-weight: 400;\"> and <\/span><span style=\"font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;\">migrate<\/span><span style=\"font-weight: 400;\"> commands:<\/span><\/p>\n<p><a href=\"https:\/\/github.com\/murilocamargos\/data-migrations-blog\/blob\/master\/store\/models.py\"><span style=\"font-weight: 400; font-size: 12px;\">GitHub<\/span><\/a><br \/>\n<!-- HTML generated using hilite.me --><\/p>\n<div style=\"overflow: auto; width: auto; padding: .6em; font-size: .85em; margin-top: -10px; background: #fbfbfb;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000; font-weight: bold;\">from<\/span> <span style=\"color: #0000ff; font-weight: bold;\">django.db<\/span> <span style=\"color: #008000; font-weight: bold;\">import<\/span> models\n\n<span style=\"color: #408080; font-style: italic;\"># Create your models here.<\/span>\n<span style=\"color: #008000; font-weight: bold;\">class<\/span> <span style=\"color: #0000ff; font-weight: bold;\">Client<\/span>(models<span style=\"color: #666666;\">.<\/span>Model):\n    name <span style=\"color: #666666;\">=<\/span> models<span style=\"color: #666666;\">.<\/span>CharField(max_length<span style=\"color: #666666;\">=255<\/span>)\n    bought <span style=\"color: #666666;\">=<\/span> models<span style=\"color: #666666;\">.<\/span>IntegerField(null<span style=\"color: #666666;\">=<\/span><span style=\"color: #008000;\">False<\/span>)\n\n<span style=\"color: #008000; font-weight: bold;\">class<\/span> <span style=\"color: #0000ff; font-weight: bold;\">Computer<\/span>(models<span style=\"color: #666666;\">.<\/span>Model):\n    brand <span style=\"color: #666666;\">=<\/span> models<span style=\"color: #666666;\">.<\/span>CharField(max_length<span style=\"color: #666666;\">=255<\/span>)\n    bought_by <span style=\"color: #666666;\">=<\/span> models<span style=\"color: #666666;\">.<\/span>ForeignKey(Client, related_name<span style=\"color: #666666;\">=<\/span><span style=\"color: #ba2121;\">'computers'<\/span>)\n<\/pre>\n<\/div>\n<p><b>Step 2. <\/b><span style=\"font-weight: 400;\">Then, we&#8217;ll add a blank migration file; here we&#8217;ll add the custom function to perform the data migration. We use the following command:<\/span><\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"overflow: auto; width: auto; padding: .6em; font-size: .85em; margin-top: -10px; background: #fbfbfb;\">\n<pre style=\"margin: 0; line-height: 125%;\">python manage<span style=\"color: #666666;\">.<\/span>py makemigrations <span style=\"color: #666666;\">--<\/span>empty store <span style=\"color: #666666;\">--<\/span>name prepopulate_bought_field\n<\/pre>\n<\/div>\n<p><span style=\"font-weight: 400;\">Note: <\/span><span style=\"font-weight: 400;\">store<\/span><span style=\"font-weight: 400;\"> is the Django app you&#8217;re working on and you can use the <\/span><span style=\"font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;\">&#8211;name<\/span><span style=\"font-weight: 400;\"> parameter to get more informative names for your migrations.<\/span><\/p>\n<p><b>Step 3. <\/b><span style=\"font-weight: 400;\">Now you&#8217;ll need to write the function for this migration (this is called the forwards function):<\/span><\/p>\n<p><a href=\"https:\/\/github.com\/murilocamargos\/data-migrations-blog\/blob\/master\/store\/migrations\/0003_data_migration.py\"><span style=\"font-weight: 400; font-size: 12px;\">GitHub<\/span><\/a><br \/>\n<!-- HTML generated using hilite.me --><\/p>\n<div style=\"overflow: auto; width: auto; padding: .6em; font-size: .85em; margin-top: -10px; background: #fbfbfb;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #408080; font-style: italic;\"># -*- coding: utf-8 -*-<\/span>\n<span style=\"color: #008000; font-weight: bold;\">from<\/span> <span style=\"color: #0000ff; font-weight: bold;\">__future__<\/span> <span style=\"color: #008000; font-weight: bold;\">import<\/span> unicode_literals\n\n<span style=\"color: #008000; font-weight: bold;\">from<\/span> <span style=\"color: #0000ff; font-weight: bold;\">django.db<\/span> <span style=\"color: #008000; font-weight: bold;\">import<\/span> migrations\n\n<span style=\"color: #008000; font-weight: bold;\">def<\/span> <span style=\"color: #0000ff;\">add_bought<\/span>(apps, schema_editor):\n    Client <span style=\"color: #666666;\">=<\/span> apps<span style=\"color: #666666;\">.<\/span>get_model(<span style=\"color: #ba2121;\">'store'<\/span>, <span style=\"color: #ba2121;\">'Client'<\/span>)\n    <span style=\"color: #008000; font-weight: bold;\">for<\/span> c <span style=\"color: #aa22ff; font-weight: bold;\">in<\/span> Client<span style=\"color: #666666;\">.<\/span>objects<span style=\"color: #666666;\">.<\/span>all():\n        c<span style=\"color: #666666;\">.<\/span>bought <span style=\"color: #666666;\">=<\/span> c<span style=\"color: #666666;\">.<\/span>computers<span style=\"color: #666666;\">.<\/span>count()\n        c<span style=\"color: #666666;\">.<\/span>save()\n\n<span style=\"color: #008000; font-weight: bold;\">class<\/span> <span style=\"color: #0000ff; font-weight: bold;\">Migration<\/span>(migrations<span style=\"color: #666666;\">.<\/span>Migration):\n    dependencies <span style=\"color: #666666;\">=<\/span> [\n        (<span style=\"color: #ba2121;\">'store'<\/span>, <span style=\"color: #ba2121;\">'0002_client_bought'<\/span>),\n    ]\n\n    operations <span style=\"color: #666666;\">=<\/span> [\n        migrations<span style=\"color: #666666;\">.<\/span>RunPython(add_bought, reverse_code<span style=\"color: #666666;\">=<\/span>migrations<span style=\"color: #666666;\">.<\/span>RunPython<span style=\"color: #666666;\">.<\/span>noop)\n    ]\n<\/pre>\n<\/div>\n<p><span style=\"font-weight: 400;\">Note that for using our <\/span><span style=\"font-weight: 400;\">Customer<\/span><span style=\"font-weight: 400;\"> model, we can&#8217;t just simply import it; this would get the most recent model that could be already changed by someone else (e.g. adding a field). To avoid this, we use <\/span><span style=\"font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;\">apps.get_model<\/span><span style=\"font-weight: 400;\"> to fetch the current migration version.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This operation can also have a rollback (or reverse function) if you want or need to, simply add it as the <\/span><span style=\"font-weight: 400;\">RunPython&#8217;s<\/span><span style=\"font-weight: 400;\"> parameter <\/span><span style=\"font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;\">reverse_code<\/span><span style=\"font-weight: 400;\"> &#8211; see more <\/span><a href=\"https:\/\/docs.djangoproject.com\/en\/2.0\/ref\/migration-operations\/#runpython\"><span style=\"font-weight: 400;\">here<\/span><\/a><span style=\"font-weight: 400;\">. In this example, we use <\/span><span style=\"font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;\">migrations.RunPython.noop<\/span><span style=\"font-weight: 400;\"> to make the migration reversible without executing any code on the rollback.<\/span><\/p>\n<p><b>Step 4. <\/b><span style=\"font-weight: 400;\">After computing and storing all data, we can change the <\/span><span style=\"font-weight: 400;\">bought<\/span><span style=\"font-weight: 400;\"> field to <\/span><span style=\"font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;\">required<\/span><span style=\"font-weight: 400;\"> in our model by setting its <\/span><span style=\"font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;\">null<\/span><span style=\"font-weight: 400;\"> property to <\/span><span style=\"font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;\">False<\/span><span style=\"font-weight: 400;\"> (it&#8217;s also possible to &nbsp;do this change on the data migration file if you want to save a migration). This step will generate another migration and you may see something like this in your screen after running <\/span><span style=\"font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;\">makemigrations<\/span><span style=\"font-weight: 400;\"> command:<\/span><\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"overflow: auto; width: auto; padding: .6em; font-size: .85em; margin-top: -10px; background: #fbfbfb;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"font-weight: 400;\">You are trying to change the nullable field 'bought' on customer to non-nullable without a default; we can't do that (the database needs something to populate existing rows).<\/span>\n<span style=\"font-weight: 400;\">Please select a fix:<\/span>\n<span style=\"font-weight: 400;\">1) Provide a one-off default now (will be set on all existing rows with a null value for this column)<\/span>\n<span style=\"font-weight: 400;\">2) Ignore for now, and let me handle existing rows with NULL myself (e.g. because you added a RunPython or RunSQL operation to handle NULL values in a previous data migration)<\/span>\n<span style=\"font-weight: 400;\">3) Quit, and let me add a default in models.py<\/span>\n<span style=\"font-weight: 400;\">Select an option:<\/span><\/pre>\n<\/div>\n<p><span style=\"font-weight: 400;\">You only need to select <\/span><span style=\"font-weight: 400;\">2<\/span><span style=\"font-weight: 400;\"> because that&#8217;s exactly what you did: you added a RunPython operation to handle <span style=\"font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;\">null<\/span> values in a previous data migration.<\/span><\/p>\n<h1><b>Second Scenario<\/b><\/h1>\n<p><span style=\"font-weight: 400;\">Now, say we have an address list and we thought it would be nice to have a many-to-many relationship so we wouldn&#8217;t need to repeat rows in address table. A few days later you realize that when users change their addresses, it changes for other users with the same address too. You now want to store a full address for each customer, even if it comes with some cost. <\/span><span style=\"font-weight: 400;\"><br \/>\n<\/span><span style=\"font-weight: 400;\">The current state of our models looks like this:<\/span><\/p>\n<p><a href=\"https:\/\/github.com\/murilocamargos\/data-migrations-blog\/blob\/4382ef2855328ee27e71d1380bcb1995083fc40c\/address_book\/models.py\"><span style=\"font-weight: 400; font-size: 12px;\">GitHub<\/span><\/a><br \/>\n<!-- HTML generated using hilite.me --><\/p>\n<div style=\"overflow: auto; width: auto; padding: .6em; font-size: .85em; margin-top: -10px; background: #fbfbfb;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000; font-weight: bold;\">from<\/span> <span style=\"color: #0000ff; font-weight: bold;\">django.db<\/span> <span style=\"color: #008000; font-weight: bold;\">import<\/span> models\n\n<span style=\"color: #408080; font-style: italic;\"># Create your models here.<\/span>\n<span style=\"color: #008000; font-weight: bold;\">class<\/span> <span style=\"color: #0000ff; font-weight: bold;\">Address<\/span>(models<span style=\"color: #666666;\">.<\/span>Model):\n    street_name <span style=\"color: #666666;\">=<\/span> models<span style=\"color: #666666;\">.<\/span>CharField(max_length<span style=\"color: #666666;\">=255<\/span>)\n\n<span style=\"color: #008000; font-weight: bold;\">class<\/span> <span style=\"color: #0000ff; font-weight: bold;\">Client<\/span>(models<span style=\"color: #666666;\">.<\/span>Model):\n    name <span style=\"color: #666666;\">=<\/span> models<span style=\"color: #666666;\">.<\/span>CharField(max_length<span style=\"color: #666666;\">=255<\/span>)\n    addresses <span style=\"color: #666666;\">=<\/span> models<span style=\"color: #666666;\">.<\/span>ManyToManyField(Address)\n<\/pre>\n<\/div>\n<p><span style=\"font-weight: 400;\">For this data migration, we&#8217;ll need an intermediary model to store addresses data before deleting it! We change our models to something like this:<\/span><\/p>\n<p><a href=\"https:\/\/github.com\/murilocamargos\/data-migrations-blog\/blob\/38e4da9f5810510ed4a5e0099252aa651f89fb90\/address_book\/models.py\"><span style=\"font-weight: 400; font-size: 12px;\">GitHub<\/span><\/a><br \/>\n<!-- HTML generated using hilite.me --><\/p>\n<div style=\"overflow: auto; width: auto; padding: .6em; font-size: .85em; margin-top: -10px; background: #fbfbfb;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000; font-weight: bold;\">from<\/span> <span style=\"color: #0000ff; font-weight: bold;\">django.db<\/span> <span style=\"color: #008000; font-weight: bold;\">import<\/span> models\n\n<span style=\"color: #408080; font-style: italic;\"># Create your models here.<\/span>\n<span style=\"color: #008000; font-weight: bold;\">class<\/span> <span style=\"color: #0000ff; font-weight: bold;\">Address<\/span>(models<span style=\"color: #666666;\">.<\/span>Model):\n    street_name <span style=\"color: #666666;\">=<\/span> models<span style=\"color: #666666;\">.<\/span>CharField(max_length<span style=\"color: #666666;\">=255<\/span>)\n\n<span style=\"color: #008000; font-weight: bold;\">class<\/span> <span style=\"color: #0000ff; font-weight: bold;\">Client<\/span>(models<span style=\"color: #666666;\">.<\/span>Model):\n    name <span style=\"color: #666666;\">=<\/span> models<span style=\"color: #666666;\">.<\/span>CharField(max_length<span style=\"color: #666666;\">=255<\/span>)\n    addresses <span style=\"color: #666666;\">=<\/span> models<span style=\"color: #666666;\">.<\/span>ManyToManyField(Address)\n\n<span style=\"color: #008000; font-weight: bold;\">class<\/span> <span style=\"color: #0000ff; font-weight: bold;\">NewAddress<\/span>(models<span style=\"color: #666666;\">.<\/span>Model):\n    street_name <span style=\"color: #666666;\">=<\/span> models<span style=\"color: #666666;\">.<\/span>CharField(max_length<span style=\"color: #666666;\">=255<\/span>)\n    client <span style=\"color: #666666;\">=<\/span> models<span style=\"color: #666666;\">.<\/span>ForeignKey(Client)\n<\/pre>\n<\/div>\n<p><span style=\"font-weight: 400;\">Similarly to what we&#8217;ve done in the previous scenario, we create a migration and write write a custom function (or <\/span><span style=\"font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;\">forwards_func<\/span><span style=\"font-weight: 400;\">) to move all data that was store on <\/span><span style=\"font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;\">Address<\/span><span style=\"font-weight: 400;\"> table to <\/span><span style=\"font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;\">NewAddress<\/span><span style=\"font-weight: 400;\"> table. It looks like this:<\/span><\/p>\n<p><a href=\"https:\/\/github.com\/murilocamargos\/data-migrations-blog\/blob\/master\/address_book\/migrations\/0002_newaddress_data_migration.py\"><span style=\"font-weight: 400; font-size: 12px;\">GitHub<\/span><\/a><br \/>\n<!-- HTML generated using hilite.me --><\/p>\n<div style=\"overflow: auto; width: auto; padding: .6em; font-size: .85em; margin-top: -10px; background: #fbfbfb;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #408080; font-style: italic;\"># -*- coding: utf-8 -*-<\/span>\n<span style=\"color: #008000; font-weight: bold;\">from<\/span> <span style=\"color: #0000ff; font-weight: bold;\">__future__<\/span> <span style=\"color: #008000; font-weight: bold;\">import<\/span> unicode_literals\n\n<span style=\"color: #008000; font-weight: bold;\">from<\/span> <span style=\"color: #0000ff; font-weight: bold;\">django.db<\/span> <span style=\"color: #008000; font-weight: bold;\">import<\/span> migrations, models\n<span style=\"color: #008000; font-weight: bold;\">import<\/span> <span style=\"color: #0000ff; font-weight: bold;\">django.db.models.deletion<\/span>\n\n<span style=\"color: #008000; font-weight: bold;\">def<\/span> <span style=\"color: #0000ff;\">migrate_data<\/span>(apps, schema_editor):\n    Client <span style=\"color: #666666;\">=<\/span> apps<span style=\"color: #666666;\">.<\/span>get_model(<span style=\"color: #ba2121;\">'address_book'<\/span>, <span style=\"color: #ba2121;\">'Client'<\/span>)\n    NewAddress <span style=\"color: #666666;\">=<\/span> apps<span style=\"color: #666666;\">.<\/span>get_model(<span style=\"color: #ba2121;\">'address_book'<\/span>, <span style=\"color: #ba2121;\">'NewAddress'<\/span>)\n\n    <span style=\"color: #008000; font-weight: bold;\">for<\/span> c <span style=\"color: #aa22ff; font-weight: bold;\">in<\/span> Client<span style=\"color: #666666;\">.<\/span>objects<span style=\"color: #666666;\">.<\/span>all():\n        <span style=\"color: #008000; font-weight: bold;\">for<\/span> a <span style=\"color: #aa22ff; font-weight: bold;\">in<\/span> c<span style=\"color: #666666;\">.<\/span>addresses<span style=\"color: #666666;\">.<\/span>all():\n            NewAddress<span style=\"color: #666666;\">.<\/span>objects<span style=\"color: #666666;\">.<\/span>create(street_name<span style=\"color: #666666;\">=<\/span>a<span style=\"color: #666666;\">.<\/span>street_name, client<span style=\"color: #666666;\">=<\/span>c)\n\n<span style=\"color: #008000; font-weight: bold;\">class<\/span> <span style=\"color: #0000ff; font-weight: bold;\">Migration<\/span>(migrations<span style=\"color: #666666;\">.<\/span>Migration):\n\n    dependencies <span style=\"color: #666666;\">=<\/span> [\n        (<span style=\"color: #ba2121;\">'address_book'<\/span>, <span style=\"color: #ba2121;\">'0001_initial'<\/span>),\n    ]\n\n    operations <span style=\"color: #666666;\">=<\/span> [\n        migrations<span style=\"color: #666666;\">.<\/span>CreateModel(\n            name<span style=\"color: #666666;\">=<\/span><span style=\"color: #ba2121;\">'NewAddress'<\/span>,\n            fields<span style=\"color: #666666;\">=<\/span>[\n                (<span style=\"color: #ba2121;\">'id'<\/span>, models<span style=\"color: #666666;\">.<\/span>AutoField(auto_created<span style=\"color: #666666;\">=<\/span><span style=\"color: #008000;\">True<\/span>, primary_key<span style=\"color: #666666;\">=<\/span><span style=\"color: #008000;\">True<\/span>, serialize<span style=\"color: #666666;\">=<\/span><span style=\"color: #008000;\">False<\/span>, verbose_name<span style=\"color: #666666;\">=<\/span><span style=\"color: #ba2121;\">'ID'<\/span>)),\n                (<span style=\"color: #ba2121;\">'street_name'<\/span>, models<span style=\"color: #666666;\">.<\/span>CharField(max_length<span style=\"color: #666666;\">=255<\/span>)),\n                (<span style=\"color: #ba2121;\">'client'<\/span>, models<span style=\"color: #666666;\">.<\/span>ForeignKey(on_delete<span style=\"color: #666666;\">=<\/span>django<span style=\"color: #666666;\">.<\/span>db<span style=\"color: #666666;\">.<\/span>models<span style=\"color: #666666;\">.<\/span>deletion<span style=\"color: #666666;\">.<\/span>CASCADE, to<span style=\"color: #666666;\">=<\/span><span style=\"color: #ba2121;\">'address_book.Client'<\/span>)),\n            ],\n        ),\n        migrations<span style=\"color: #666666;\">.<\/span>RunPython(migrate_data, reverse_code<span style=\"color: #666666;\">=<\/span>migrations<span style=\"color: #666666;\">.<\/span>RunPython<span style=\"color: #666666;\">.<\/span>noop)\n    ]\n<\/pre>\n<\/div>\n<p><span style=\"font-weight: 400;\">We can now remove our old <\/span><span style=\"font-weight: 400;\">Address<\/span><span style=\"font-weight: 400;\"> model, then run <\/span><span style=\"font-weight: 400;\">makemigrations <\/span><span style=\"font-weight: 400;\">and rename your <\/span><span style=\"font-weight: 400;\">NewAddress<\/span><span style=\"font-weight: 400;\"> model to <\/span><span style=\"font-weight: 400;\">Address<\/span><span style=\"font-weight: 400;\">. It&#8217;s important to run <\/span><span style=\"font-weight: 400;\">makemigrations<\/span><span style=\"font-weight: 400;\"> in between these two operations, otherwise Django will treat <\/span><span style=\"font-weight: 400;\">NewAddress<\/span><span style=\"font-weight: 400;\"> as if it was the old <\/span><span style=\"font-weight: 400;\">Address<\/span><span style=\"font-weight: 400;\">.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Note that even using <\/span><span style=\"font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;\">migrations.RunPython.noop<\/span><span style=\"font-weight: 400;\">, this migration is not reversible because we&#8217;re deleting and renaming models. If you need it to be reversible, you should write another custom function that does the rollback.<\/span><\/p>\n<h1><b>Conclusions<\/b><\/h1>\n<p><span style=\"font-weight: 400;\">These operations can be very harmful to your data if used improperly, so it&#8217;s always a good idea to have a database dump before doing something like this in production. These scenarios we used as example are a bit silly, but it&#8217;s enough to get the idea of how to apply data migrations to solve data consistency issues.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">You can also make <\/span><a href=\"https:\/\/docs.djangoproject.com\/pt-br\/1.11\/howto\/initial-data\/\"><span style=\"font-weight: 400;\">fixtures<\/span><\/a><span style=\"font-weight: 400;\"> for loading some initial data to your apps or just importing a text file on any of your data migrations and running a forwards function to get them in your database.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">As Sir Oliver Wendell Holmes would say, <\/span><span style=\"font-weight: 400;\">The young man knows the rules, but the old man knows the exceptions<\/span><span style=\"font-weight: 400;\">. So if you know any exceptions, please let us know, help is very much appreciated.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The code used in this blogpost is available on <\/span><a href=\"https:\/\/github.com\/murilocamargos\/data-migrations-blog\"><span style=\"font-weight: 400;\">GitHub<\/span><\/a><span style=\"font-weight: 400;\">.<\/span><\/p>\n<h3><b>Good references<\/b><\/h3>\n<ul>\n<li><a href=\"https:\/\/realpython.com\/blog\/python\/data-migrations\/\"><span style=\"font-weight: 400;\">https:\/\/realpython.com\/blog\/python\/data-migrations\/<\/span><\/a><\/li>\n<li><a href=\"https:\/\/docs.djangoproject.com\/en\/2.0\/topics\/migrations\/#data-migrations\"><span style=\"font-weight: 400;\">https:\/\/docs.djangoproject.com\/en\/2.0\/topics\/migrations\/#data-migrations<\/span><\/a><\/li>\n<li><a href=\"https:\/\/simpleisbetterthancomplex.com\/tutorial\/2017\/09\/26\/how-to-create-django-data-migrations.html\"><span style=\"font-weight: 400;\">https:\/\/simpleisbetterthancomplex.com\/tutorial\/2017\/09\/26\/how-to-create-django-data-migrations.html<\/span><\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Django built-in migrations were designed as a way of propagating the changes you make on the models to the database. Migrations exist mostly to keep your code in sync with your schema and to provide a good way of versioning it. We just need a couple of commands to get our apps up and running [&hellip;]<\/p>\n","protected":false},"author":65,"featured_media":9327,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[471,1163],"tags":[1148,1155],"class_list":["post-5907","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-engenharia","category-process-br","tag-tag-development-br","tag-tag-django-br"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v21.1 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Keeping data integrity with Django migrations | Cheesecake Labs<\/title>\n<meta name=\"robots\" content=\"noindex, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<meta property=\"og:locale\" content=\"pt_BR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Keeping data integrity with Django migrations | Cheesecake Labs\" \/>\n<meta property=\"og:description\" content=\"Django built-in migrations were designed as a way of propagating the changes you make on the models to the database. Migrations exist mostly to keep your code in sync with your schema and to provide a good way of versioning it. We just need a couple of commands to get our apps up and running [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blog-stg.cheesecakelabs.com\/br\/keeping-data-integrity-django-migrations\/\" \/>\n<meta property=\"og:site_name\" content=\"Cheesecake Labs\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/cheesecakelabs\" \/>\n<meta property=\"article:published_time\" content=\"2018-04-27T17:14:53+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-07-01T17:24:15+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2018\/04\/murilo_blogpost-03.png\" \/>\n\t<meta property=\"og:image:width\" content=\"2500\" \/>\n\t<meta property=\"og:image:height\" content=\"888\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Cheesecake Labs\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@cheesecakelabs\" \/>\n<meta name=\"twitter:site\" content=\"@cheesecakelabs\" \/>\n<meta name=\"twitter:label1\" content=\"Escrito por\" \/>\n\t<meta name=\"twitter:data1\" content=\"\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. tempo de leitura\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/blog-stg.cheesecakelabs.com\/br\/keeping-data-integrity-django-migrations\/\",\"url\":\"https:\/\/blog-stg.cheesecakelabs.com\/br\/keeping-data-integrity-django-migrations\/\",\"name\":\"Keeping data integrity with Django migrations | Cheesecake Labs\",\"isPartOf\":{\"@id\":\"https:\/\/blog-stg.cheesecakelabs.com\/br\/#website\"},\"datePublished\":\"2018-04-27T17:14:53+00:00\",\"dateModified\":\"2022-07-01T17:24:15+00:00\",\"author\":{\"@type\":\"person\",\"name\":\"Murilo Camargos\"},\"breadcrumb\":{\"@id\":\"https:\/\/blog-stg.cheesecakelabs.com\/br\/keeping-data-integrity-django-migrations\/#breadcrumb\"},\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/blog-stg.cheesecakelabs.com\/br\/keeping-data-integrity-django-migrations\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/blog-stg.cheesecakelabs.com\/br\/keeping-data-integrity-django-migrations\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/blog-stg.cheesecakelabs.com\/br\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Keeping data integrity with Django migrations\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/blog-stg.cheesecakelabs.com\/br\/#website\",\"url\":\"https:\/\/blog-stg.cheesecakelabs.com\/br\/\",\"name\":\"Cheesecake Labs\",\"description\":\"Empresa de desenvolvimento e design de aplicativos mobile &amp; web que est\u00e1 reinventando o desenvolvimento de produtos com times remotos. N\u00f3s desenvolvemos aplicativos iOS, Android e aplica\u00e7\u00f5es Web com as melhores empresas dos EUA, do Brasil e do mundo.\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/blog-stg.cheesecakelabs.com\/br\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"pt-BR\"},{\"@type\":\"Person\",\"name\":\"Murilo Camargos\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\/\/blog-stg.cheesecakelabs.com\/br\/#\/schema\/person\/image\/\",\"url\":false,\"contentUrl\":false,\"caption\":\"Murilo Camargos\"},\"description\":\"10 years of experience in Marketing and Sales in the Technology sector. My main purpose is help, support and structure efficient operations and also develop independent and multidisciplinary teams.\",\"url\":\"https:\/\/blog-stg.cheesecakelabs.com\/br\/\/autor\/murilo-camargos\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Keeping data integrity with Django migrations | Cheesecake Labs","robots":{"index":"noindex","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"og_locale":"pt_BR","og_type":"article","og_title":"Keeping data integrity with Django migrations | Cheesecake Labs","og_description":"Django built-in migrations were designed as a way of propagating the changes you make on the models to the database. Migrations exist mostly to keep your code in sync with your schema and to provide a good way of versioning it. We just need a couple of commands to get our apps up and running [&hellip;]","og_url":"https:\/\/blog-stg.cheesecakelabs.com\/br\/keeping-data-integrity-django-migrations\/","og_site_name":"Cheesecake Labs","article_publisher":"https:\/\/www.facebook.com\/cheesecakelabs","article_published_time":"2018-04-27T17:14:53+00:00","article_modified_time":"2022-07-01T17:24:15+00:00","og_image":[{"width":2500,"height":888,"url":"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2018\/04\/murilo_blogpost-03.png","type":"image\/png"}],"author":"Cheesecake Labs","twitter_card":"summary_large_image","twitter_creator":"@cheesecakelabs","twitter_site":"@cheesecakelabs","twitter_misc":{"Escrito por":null,"Est. tempo de leitura":"7 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/blog-stg.cheesecakelabs.com\/br\/keeping-data-integrity-django-migrations\/","url":"https:\/\/blog-stg.cheesecakelabs.com\/br\/keeping-data-integrity-django-migrations\/","name":"Keeping data integrity with Django migrations | Cheesecake Labs","isPartOf":{"@id":"https:\/\/blog-stg.cheesecakelabs.com\/br\/#website"},"datePublished":"2018-04-27T17:14:53+00:00","dateModified":"2022-07-01T17:24:15+00:00","author":{"@type":"person","name":"Murilo Camargos"},"breadcrumb":{"@id":"https:\/\/blog-stg.cheesecakelabs.com\/br\/keeping-data-integrity-django-migrations\/#breadcrumb"},"inLanguage":"pt-BR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blog-stg.cheesecakelabs.com\/br\/keeping-data-integrity-django-migrations\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/blog-stg.cheesecakelabs.com\/br\/keeping-data-integrity-django-migrations\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/blog-stg.cheesecakelabs.com\/br\/"},{"@type":"ListItem","position":2,"name":"Keeping data integrity with Django migrations"}]},{"@type":"WebSite","@id":"https:\/\/blog-stg.cheesecakelabs.com\/br\/#website","url":"https:\/\/blog-stg.cheesecakelabs.com\/br\/","name":"Cheesecake Labs","description":"Empresa de desenvolvimento e design de aplicativos mobile &amp; web que est\u00e1 reinventando o desenvolvimento de produtos com times remotos. N\u00f3s desenvolvemos aplicativos iOS, Android e aplica\u00e7\u00f5es Web com as melhores empresas dos EUA, do Brasil e do mundo.","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blog-stg.cheesecakelabs.com\/br\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"pt-BR"},{"@type":"Person","name":"Murilo Camargos","image":{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/blog-stg.cheesecakelabs.com\/br\/#\/schema\/person\/image\/","url":false,"contentUrl":false,"caption":"Murilo Camargos"},"description":"10 years of experience in Marketing and Sales in the Technology sector. My main purpose is help, support and structure efficient operations and also develop independent and multidisciplinary teams.","url":"https:\/\/blog-stg.cheesecakelabs.com\/br\/\/autor\/murilo-camargos\/"}]}},"_links":{"self":[{"href":"https:\/\/blog-stg.cheesecakelabs.com\/br\/wp-json\/wp\/v2\/posts\/5907","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog-stg.cheesecakelabs.com\/br\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog-stg.cheesecakelabs.com\/br\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog-stg.cheesecakelabs.com\/br\/wp-json\/wp\/v2\/users\/65"}],"replies":[{"embeddable":true,"href":"https:\/\/blog-stg.cheesecakelabs.com\/br\/wp-json\/wp\/v2\/comments?post=5907"}],"version-history":[{"count":1,"href":"https:\/\/blog-stg.cheesecakelabs.com\/br\/wp-json\/wp\/v2\/posts\/5907\/revisions"}],"predecessor-version":[{"id":10246,"href":"https:\/\/blog-stg.cheesecakelabs.com\/br\/wp-json\/wp\/v2\/posts\/5907\/revisions\/10246"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog-stg.cheesecakelabs.com\/br\/wp-json\/wp\/v2\/media\/9327"}],"wp:attachment":[{"href":"https:\/\/blog-stg.cheesecakelabs.com\/br\/wp-json\/wp\/v2\/media?parent=5907"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog-stg.cheesecakelabs.com\/br\/wp-json\/wp\/v2\/categories?post=5907"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog-stg.cheesecakelabs.com\/br\/wp-json\/wp\/v2\/tags?post=5907"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}