{"id":5904,"date":"2018-04-27T17:14:53","date_gmt":"2018-04-27T17:14:53","guid":{"rendered":"https:\/\/cheesecakelabs.com\/blog\/?p=5904\/"},"modified":"2026-08-25T15:52:40","modified_gmt":"2026-08-25T15:52:40","slug":"keeping-data-integrity-django-migrations","status":"publish","type":"post","link":"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/","title":{"rendered":"Keeping data integrity with Django migrations"},"content":{"rendered":"\n<p><span style=\"font-weight: 400;\"><a href=\"https:\/\/cheesecakelabs.com\/blog\/blog\/django-framework-app-development\/\" target=\"_blank\" rel=\"noreferrer noopener\">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:\/\/cheesecakelabs.com\/blog\/blog\/really-annoys-django-migrations\/\" target=\"_blank\" rel=\"noreferrer noopener\"><span style=\"font-weight: 400;\">not<\/span><\/a><span style=\"font-weight: 400;\">.<\/span><\/p>\n\n\n\n<!--more-->\n\n\n\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?<\/span><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">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\n\n\n<h2 class=\"wp-block-heading\"><b>First Scenario<\/b><\/h2>\n\n\n\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\n\n\n<p><a href=\"https:\/\/github.com\/murilocamargos\/data-migrations-blog\/blob\/6c38dde2f15e569dc8d03df3743e7be331b61147\/store\/models.py\" target=\"_blank\" rel=\"noreferrer noopener\">GitHub<\/a><\/p>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:100%\">\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<\/div>\n<\/div>\n\n\n\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.<\/span><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">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\/\" target=\"_blank\" rel=\"noreferrer noopener\"><span style=\"font-weight: 400;\">annotations<\/span><\/a><span style=\"font-weight: 400;\"> with a Count aggregation.<\/span><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">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\n\n\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\n\n\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\n\n\n<p><a href=\"https:\/\/github.com\/murilocamargos\/data-migrations-blog\/blob\/master\/store\/models.py\" target=\"_blank\" rel=\"noreferrer noopener\">GitHub<\/a><\/p>\n\n\n\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\n\n\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\n\n\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\n\n\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\n\n\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\n\n\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\n\n\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\n\n\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\n\n\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\n\n\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\n\n\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\n\n\n<h1 class=\"wp-block-heading\"><b>Second Scenario<\/b><\/h1>\n\n\n\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><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">The current state of our models looks like this<\/span>:<\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/murilocamargos\/data-migrations-blog\/blob\/4382ef2855328ee27e71d1380bcb1995083fc40c\/address_book\/models.py\">GitHub<\/a><\/p>\n\n\n\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\n\n\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\n\n\n<p><a href=\"https:\/\/github.com\/murilocamargos\/data-migrations-blog\/blob\/38e4da9f5810510ed4a5e0099252aa651f89fb90\/address_book\/models.py\" target=\"_blank\" rel=\"noreferrer noopener\">GitHub<\/a><\/p>\n\n\n\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\n\n\n<p><span style=\"font-weight: 400;\">Similarly to what we&#8217;ve done in the previous scenario, we create a migration and 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.<\/span><\/p>\n\n\n\n<p><span style=\"font-weight: 400;\">It looks like this<\/span>:<\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/murilocamargos\/data-migrations-blog\/blob\/master\/address_book\/migrations\/0002_newaddress_data_migration.py\" target=\"_blank\" rel=\"noreferrer noopener\">GitHub<\/a><\/p>\n\n\n\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\n\n\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\n\n\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\n\n\n<h2 class=\"wp-block-heading\"><b>Conclusions<\/b><\/h2>\n\n\n\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\n\n\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\/\" target=\"_blank\" rel=\"noreferrer noopener\"><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\n\n\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\n\n\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\" target=\"_blank\" rel=\"noreferrer noopener\"><span style=\"font-weight: 400;\">GitHub<\/span><\/a><span style=\"font-weight: 400;\">.<\/span><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><b>Good references<\/b><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/realpython.com\/blog\/python\/data-migrations\/\" target=\"_blank\" rel=\"noreferrer noopener\"><span style=\"font-weight: 400;\">https:\/\/realpython.com\/blog\/python\/data-migrations\/<\/span><\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/docs.djangoproject.com\/en\/2.0\/topics\/migrations\/#data-migrations\" target=\"_blank\" rel=\"noreferrer noopener\"><span style=\"font-weight: 400;\">https:\/\/docs.djangoproject.com\/en\/2.0\/topics\/migrations\/#data-migrations<\/span><\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/simpleisbetterthancomplex.com\/tutorial\/2017\/09\/26\/how-to-create-django-data-migrations.html\" target=\"_blank\" rel=\"noreferrer noopener\"><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":5905,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_yoast_wpseo_title":"","_yoast_wpseo_metadesc":"Learn how to keep data integrity with Django migrations while propagating model changes and maintaining synchronization with your database schema.","_yoast_wpseo_meta-robots-noindex":"","_yoast_wpseo_canonical":"","ai_summary":"<p>Django's built-in migrations keep code and database schema in sync, but some changes\u2014like adding a required field to an existing table or converting a many-to-many relationship to a foreign key without losing data\u2014require data migrations. The post walks through adding a required computed field by first creating it as nullable, generating an empty migration with a RunPython forwards function (using apps.get_model to fetch the current model version) to populate existing rows, then making the field non-nullable. For converting a many-to-many to a foreign key, the approach uses an intermediary NewAddress model with a RunPython function to copy data, followed by removing the old model and renaming NewAddress, with makemigrations run between steps to avoid Django treating them as the same model. Data migrations can harm data if misused, so taking a database dump before running them in production is recommended, and reverse_code (such as migrations.RunPython.noop) can be specified to control rollback behavior.<\/p>","ai_summary_en":"Django's built-in migrations keep code and database schema in sync, but some changes\u2014like adding a required field to an existing table or converting a many-to-many relationship to a foreign key without losing data\u2014require data migrations.\nThe post walks through adding a required computed field by first creating it as nullable, generating an empty migration with a RunPython forwards function (using apps.get_model to fetch the current model version) to populate existing rows, then making the field non-nullable.\nFor converting a many-to-many to a foreign key, the approach uses an intermediary NewAddress model with a RunPython function to copy data, followed by removing the old model and renaming NewAddress, with makemigrations run between steps to avoid Django treating them as the same model.\nData migrations can harm data if misused, so taking a database dump before running them in production is recommended, and reverse_code (such as migrations.RunPython.noop) can be specified to control rollback behavior.","ai_summary_pt-br":"","footnotes":"","ckl_wpml_lang":"","ckl_wpml_source_id":0,"ckl_wpml_status":""},"categories":[1425,1371,432],"tags":[305,350],"class_list":["post-5904","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-product-engineering","category-data-analytics","category-engineering","tag-tag-development","tag-tag-django"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Keeping data integrity with Django migrations<\/title>\n<meta name=\"description\" content=\"Learn how to keep data integrity with Django migrations while propagating model changes and maintaining synchronization with your database schema.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Keeping data integrity with Django migrations\" \/>\n<meta property=\"og:description\" content=\"Learn how to keep data integrity with Django migrations while propagating model changes and maintaining synchronization with your database schema.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cheesecakelabs.com\/blog\/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=\"2026-08-25T15:52:40+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=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/\"},\"author\":{\"name\":\"Murilo Camargos\"},\"headline\":\"Keeping data integrity with Django migrations\",\"datePublished\":\"2018-04-27T17:14:53+00:00\",\"dateModified\":\"2026-08-25T15:52:40+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/\"},\"wordCount\":950,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2018\/04\/murilo_blogpost-03.png\",\"keywords\":[\"development\",\"Django\"],\"articleSection\":[\"Product Engineering\",\"Data &amp; Analytics\",\"Engineering\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/\",\"url\":\"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/\",\"name\":\"Keeping data integrity with Django migrations\",\"isPartOf\":{\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2018\/04\/murilo_blogpost-03.png\",\"datePublished\":\"2018-04-27T17:14:53+00:00\",\"dateModified\":\"2026-08-25T15:52:40+00:00\",\"description\":\"Learn how to keep data integrity with Django migrations while propagating model changes and maintaining synchronization with your database schema.\",\"breadcrumb\":{\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/#primaryimage\",\"url\":\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2018\/04\/murilo_blogpost-03.png\",\"contentUrl\":\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2018\/04\/murilo_blogpost-03.png\",\"width\":2500,\"height\":888,\"caption\":\"murilo_blogpost | | Cheesecake Labs\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cheesecakelabs.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Keeping data integrity with Django migrations\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/#website\",\"url\":\"https:\/\/cheesecakelabs.com\/blog\/\",\"name\":\"Cheesecake Labs\",\"description\":\"AI Implementation, Data and Product Engineering\",\"publisher\":{\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cheesecakelabs.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/#organization\",\"name\":\"Cheesecake Labs\",\"alternateName\":\"Cheesecake Labs Inc\",\"url\":\"https:\/\/cheesecakelabs.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/cheesecakelabs.com\/#logo\",\"url\":\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2022\/06\/cheesecake-labs-1.png\",\"contentUrl\":\"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2022\/06\/cheesecake-labs-1.png\",\"caption\":\"Cheesecake Labs\",\"inLanguage\":\"en\"},\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/cheesecakelabs.com\/#primary-image\",\"url\":\"https:\/\/ckl-website-v4-strapi-prod.s3.us-east-2.amazonaws.com\/ai_software_development_company_83fb512983.webp\",\"contentUrl\":\"https:\/\/ckl-website-v4-strapi-prod.s3.us-east-2.amazonaws.com\/ai_software_development_company_83fb512983.webp\",\"width\":1920,\"height\":1080,\"caption\":\"Cheesecake Labs \u2014 AI, Data & Blockchain software development services\",\"inLanguage\":\"en\"},\"sameAs\":[\"https:\/\/www.facebook.com\/cheesecakelabs\",\"https:\/\/x.com\/cheesecakelabs\",\"https:\/\/www.instagram.com\/cheesecakelabs\/\",\"https:\/\/www.linkedin.com\/company\/cheesecake-labs\/\",\"https:\/\/www.youtube.com\/channel\/UCdGEQ5AHJcmIlaOaI5fGGVA\",\"https:\/\/clutch.co\/profile\/cheesecake-labs\",\"https:\/\/www.behance.net\/cheesecakelabs\",\"https:\/\/dribbble.com\/cheesecakelabs\",\"https:\/\/www.designrush.com\/agency\/profile\/cheesecake-labs\",\"https:\/\/www.g2.com\/products\/cheesecake-labs\/reviews\"],\"description\":\"Cheesecake Labs is a software development studio that designs and builds custom digital products \u2014 web, mobile, and platforms \u2014 combining product design and high-performance engineering.\",\"foundingDate\":\"2013\"},{\"@type\":\"Person\",\"name\":\"Murilo Camargos\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cheesecakelabs.com\/blog\/#\/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:\/\/cheesecakelabs.com\/blog\/autor\/murilo-3\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Keeping data integrity with Django migrations","description":"Learn how to keep data integrity with Django migrations while propagating model changes and maintaining synchronization with your database schema.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/","og_locale":"en_US","og_type":"article","og_title":"Keeping data integrity with Django migrations","og_description":"Learn how to keep data integrity with Django migrations while propagating model changes and maintaining synchronization with your database schema.","og_url":"https:\/\/cheesecakelabs.com\/blog\/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":"2026-08-25T15:52:40+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":{"Written by":null,"Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/#article","isPartOf":{"@id":"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/"},"author":{"name":"Murilo Camargos"},"headline":"Keeping data integrity with Django migrations","datePublished":"2018-04-27T17:14:53+00:00","dateModified":"2026-08-25T15:52:40+00:00","mainEntityOfPage":{"@id":"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/"},"wordCount":950,"commentCount":2,"publisher":{"@id":"https:\/\/cheesecakelabs.com\/blog\/#organization"},"image":{"@id":"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/#primaryimage"},"thumbnailUrl":"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2018\/04\/murilo_blogpost-03.png","keywords":["development","Django"],"articleSection":["Product Engineering","Data &amp; Analytics","Engineering"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/","url":"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/","name":"Keeping data integrity with Django migrations","isPartOf":{"@id":"https:\/\/cheesecakelabs.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/#primaryimage"},"image":{"@id":"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/#primaryimage"},"thumbnailUrl":"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2018\/04\/murilo_blogpost-03.png","datePublished":"2018-04-27T17:14:53+00:00","dateModified":"2026-08-25T15:52:40+00:00","description":"Learn how to keep data integrity with Django migrations while propagating model changes and maintaining synchronization with your database schema.","breadcrumb":{"@id":"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/#primaryimage","url":"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2018\/04\/murilo_blogpost-03.png","contentUrl":"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2018\/04\/murilo_blogpost-03.png","width":2500,"height":888,"caption":"murilo_blogpost | | Cheesecake Labs"},{"@type":"BreadcrumbList","@id":"https:\/\/cheesecakelabs.com\/blog\/keeping-data-integrity-django-migrations\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cheesecakelabs.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Keeping data integrity with Django migrations"}]},{"@type":"WebSite","@id":"https:\/\/cheesecakelabs.com\/blog\/#website","url":"https:\/\/cheesecakelabs.com\/blog\/","name":"Cheesecake Labs","description":"AI Implementation, Data and Product Engineering","publisher":{"@id":"https:\/\/cheesecakelabs.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cheesecakelabs.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cheesecakelabs.com\/blog\/#organization","name":"Cheesecake Labs","alternateName":"Cheesecake Labs Inc","url":"https:\/\/cheesecakelabs.com\/","logo":{"@type":"ImageObject","@id":"https:\/\/cheesecakelabs.com\/#logo","url":"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2022\/06\/cheesecake-labs-1.png","contentUrl":"https:\/\/ckl-website-static.s3.amazonaws.com\/wp-content\/uploads\/2022\/06\/cheesecake-labs-1.png","caption":"Cheesecake Labs","inLanguage":"en"},"image":{"@type":"ImageObject","@id":"https:\/\/cheesecakelabs.com\/#primary-image","url":"https:\/\/ckl-website-v4-strapi-prod.s3.us-east-2.amazonaws.com\/ai_software_development_company_83fb512983.webp","contentUrl":"https:\/\/ckl-website-v4-strapi-prod.s3.us-east-2.amazonaws.com\/ai_software_development_company_83fb512983.webp","width":1920,"height":1080,"caption":"Cheesecake Labs \u2014 AI, Data & Blockchain software development services","inLanguage":"en"},"sameAs":["https:\/\/www.facebook.com\/cheesecakelabs","https:\/\/x.com\/cheesecakelabs","https:\/\/www.instagram.com\/cheesecakelabs\/","https:\/\/www.linkedin.com\/company\/cheesecake-labs\/","https:\/\/www.youtube.com\/channel\/UCdGEQ5AHJcmIlaOaI5fGGVA","https:\/\/clutch.co\/profile\/cheesecake-labs","https:\/\/www.behance.net\/cheesecakelabs","https:\/\/dribbble.com\/cheesecakelabs","https:\/\/www.designrush.com\/agency\/profile\/cheesecake-labs","https:\/\/www.g2.com\/products\/cheesecake-labs\/reviews"],"description":"Cheesecake Labs is a software development studio that designs and builds custom digital products \u2014 web, mobile, and platforms \u2014 combining product design and high-performance engineering.","foundingDate":"2013"},{"@type":"Person","name":"Murilo Camargos","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cheesecakelabs.com\/blog\/#\/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:\/\/cheesecakelabs.com\/blog\/autor\/murilo-3\/"}]}},"_links":{"self":[{"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/posts\/5904","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/users\/65"}],"replies":[{"embeddable":true,"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/comments?post=5904"}],"version-history":[{"count":3,"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/posts\/5904\/revisions"}],"predecessor-version":[{"id":15405,"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/posts\/5904\/revisions\/15405"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/media\/5905"}],"wp:attachment":[{"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/media?parent=5904"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/categories?post=5904"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cheesecakelabs.com\/blog\/wp-json\/wp\/v2\/tags?post=5904"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}