I have some questions on Squashing in Django 1.8. I've squashed a few migration files into one but not quite sure how to do the 2 actions as specified in the djangoprojects docs.
After this has been done, you must then transition the squashed migration to a normal initial migration, by:
-Deleting all the migration files it replaces
-Removing the replaces argument in the Migration class of the squashed migration (this is how Django tells that it is a squashed migration)
Do I just delete the migration files in the migration file using normal rm command?
Do I just vim the migration file "0001_squashed_xxx" and remove the part "replaces = []"?
Also, after I run the squashed migration, the migration (original is 0010) became 0001 automatically. Is this the expected behavior?
Any help would be great. Thanks!
Do I just delete the migration files in the migration file using normal rm command?
Do I just vim the migration file "0001_squashed_xxx" and remove the part "replaces = []"?
Yes and yes, but only AFTER you've run the squashed migrations on all your production sites.
Also, you should ensure that none of your other migrations depend on the migrations you're about to delete. If they do, you should change those dependencies to point at the corresponding squashed migrations instead.
Also, after I run the squashed migration, the migration (original is 0010) became 0001 automatically. Is this the expected behavior?
This is because squashed migrations are given the name <start_migration>_squashed_<end_migration>. So if you squashed from 0001_initial to 0010_blah, the squashed migration will have the name 0001_initial_squashed_0010_blah and thus its code will start with 0001. But the numbering doesn't really mean anything, it's just there so that your migrations are nicely ordered when listed in a directory.
Related
I have django app already online and running. I created new model and if I do the makemigrations, it is working fine, but if I want to migrate it, then I receive Running migrations:No migrations to apply. Even though that I made a change. The change is also in the migration file. I am using postgresql with it. I tried to delete the migration file and create it once more, but it did not help. Any idea what might be wrong?
Looks like some migrations are marked as applied incorrectly in the database. This can be solved by using the --fake flag [Django docs] to mark an appropriate migration as applied / some migrations as unapplied.
Suppose that your app is named myapp and the migration 0004 is applied properly to the database (you are trying to apply 0005 or further which doesn't work) then you will run the following command:
python manage.py migrate myapp 0004 --fake
Note: myapp and 0004 is an example, do this according to your apps name and which migrations are applied.
Edit: It appears that you have deleted the migrations. But thankfully have some version control in place. Best would be to get the migration files back from the version control. If for some reason you are unable to do that, revert the models to how they were before their changes and make sure no migration files exist for now. Next generate the migration files by running makemigrations (check that they are as expected and your database state corresponds to these generated files). Next run the following two commands:
python manage.py migrate <appname> zero --fake
python manage.py migrate <appname> --fake
The first one will mark all migrations as unapplied for the app. The second one will mark all the migrations as applied. Next you will add the changes you wanted to make back to the models and migrate again.
I had 10 migrations and I wanted to keep them in one file . So I squash them using ./manage.py squashmigrations accounts . Now I had 11 files including init and squash file. so I deleted 9 other files and kept init and squash and run migration and migrate .
Now want to ask Is this proper way ? and I have another app with same scenario should I do same to that ?
Yes that's basically the way to do it :)
Django has a great documentation about how to squash migrations and the appropriate workflow. See https://docs.djangoproject.com/en/3.1/topics/migrations/#migration-squashing
In short,
Create a squash migration and add it to your other migrations
Once you applied all current migrations to your environment(s), you can delete the old files as you did.
But additionally, you should
make sure other apps that referenced a deleted migration are updated to link to your new squash migration file
delete the replaces attribute inside of the squash migration, so that it is considered as a plain migration (and not a squash migration anymore)
Then you're done and you can repeat the process for other apps, the same one again once more migrations accumulated again.
If I run python -Wall manage.py test this warning (and similar) occurs:
/local/lib/python2.7/site-packages/django/db/models/fields/__init__.py:1453:
RuntimeWarning: DateTimeField SignUpUser.signup_time received a naive datetime (2018-03-17 21:27:22.620074) while time zone support is active.RuntimeWarning)
But there is no such field for the model SignUpUser anymore. It's called signup_timestamp. The same error occurs on other fields. To fix these I changed datetime.now to the django built-in timezone considering timezone.now. But the error messages also doesn't disappear. I think this occurs because of an old migration.
The site is already in production, but only me is developing. How should I fix this? Resetting all migration files and redo the migration with --fake-initial?
I ran into a similar problem. I had defined the default value for a DateTimeField with datetime.now and switched to timezone.now.
I had created migrations after each model change (proably to test them). This lead to one migration defining the default value without the timezone (field=models.DateTimeField(default=datetime.datetime(2018, 8, 2, 22, 15, 4, 702061)),) and the next migration would fix this issue and add the timezone (field=models.DateTimeField(default=datetime.datetime(2018, 8, 3, 19, 22, 32, 951341, tzinfo=utc)),).
When running the tests for the model (python manage.py test app_name) then resulted in: [...]/django/db/models/fields/__init__.py:1423: RuntimeWarning: DateTimeField Job.sub_date received a naive datetime (2018-08-02 22:15:04.702061) while time zone support is active.
It seems like Django tries to apply the migrations to a database in which the timezone awareness is already defined. Not sure why it does that but that seems to be going on.
To prevent the warning occurring I had to squash the migrations up to the migration that changed the default value of the DateTimeFiled to be timezone aware.
In my case this was migration 0007, while 0006 added the default value without the timezone awareness.
So the command to create the squash was:
$ python manage.py squashmigrations app_name 0007
This created a new migration file 0001_squashed_0007_auto_20180803_2122.py which contains all the changes done by the migrations 0001 through 0007. As the documentation says, this happens in an optimized manner so that only the final result of a series of migrations is build without the intermediate steps.
On new installs, instead of running the separate migrations 0001 through 0007 only the new squashed migration will be run.
You should keep the original migrations around for some time, to make sure the squashing did not introduce any issues:
Once you’ve squashed your migration, you should then commit it alongside the migrations it replaces and distribute this change to all running instances of your application, making sure that they run migrate to store the change in their database.
You must then transition the squashed migration to a normal migration by:
Deleting all the migration files it replaces.
Updating all migrations that depend on the deleted migrations to depend on the squashed migration instead.
Removing the replaces attribute in the Migration class of the squashed migration (this is how Django tells that it is a squashed migration).
For example, I have 50 migrations and i have squashed all the migrations to 0001_initial.py and after reaching again 50 migrations. How do i squash the migrations?
Before you can squash your new migrations, you need to transition your squashed migrations into normal migrations as outlined in the documentation (at the end of the section):
You must then transition the squashed migration to a normal migration
by:
Deleting all the migration files it replaces.
Updating all migrations that depend on the deleted migrations to depend on the squashed migration instead.
Removing the replaces attribute in the Migration
class of the squashed migration (this is how Django tells that it is a
squashed migration).
Once you have removed the original migrations that were squashed, along with all references, the squashed migrations become the "normal" migrations, and you will be able to squash these again.
python manage.py squashmigrations <appname> <squashfrom> <squashto>
python manage.py help squashmigrations
If you have already squashed once, your squash file contains this code.
replaces = [('model_name', '0001_auto...
After commenting the code above.
# replaces = [('model_name', '0001_auto...
you can squash again.
python manage.py squashmigrations app_name 000x
Django documentation says we could delete migrations after squashing them:
You should commit this migration but leave the old ones in place; the
new migration will be used for new installs. Once you are sure all
instances of the code base have applied the migrations you squashed,
you can delete them.
Here, does deleting means deleting only the migration files, or the entries in the django_migrations table as well?
Here is some background: I have only the development machine, so just one code base. After squashing some of the migrations that I had already applied, I deleted the files and the database entries. Tested if this is OK by making migrations, it did not find anything. So, everything looked good. Next day, I had to change something, and made migration. When I tried to migrate, it tried to apply the squashed migration too (which was applied part by part before being squashed). So, I had to go back and recreate the entries in the django_migrations table. So, it seems like I had to keep the database entries. I am trying to make sure before I mess up anything again, and understand why it looked fine first, and then tried to apply the squashed migration.
Squashed migrations are never marked as applied, which will be fixed in 1.8.3 (see #24628).
The steps to remove the old migrations are:
Make sure all replaced migrations are applied (or none of them).
Remove the old migration files, remove the replaces attribute from the squashed migrations.
(Workaround) Run ./manage.py migrate <app_label> <squashed_migration> --fake.
The last step won't be necessary when 1.8.3 arrives.
Converting squashed migrations has gotten easier since the question was posted. I posted a small sample project that shows how to squash migrations with circular dependencies, and it also shows how to convert the squashed migration into a regular migration after all the installations have migrated past the squash point.
As the Django documentation says:
You must then transition the squashed migration to a normal migration by:
Deleting all the migration files it replaces.
Updating all migrations that depend on the deleted migrations to depend on the squashed migration instead.
Removing the replaces attribute in the Migration class of the squashed migration (this is how Django tells that it is a squashed migration).
I'm no expert by any means, but I just squashed my migrations, and ended up doing the following:
Ran this query to removed the old migrations (squashed)
DELETE FROM south_migrationhistory;
Run this management command to remove the ghosted migrations
./manage.py migrate --fake --delete-ghost-migrations
Django 1.7 also has squashmigrations