How would you create a 'manual' django migration? - django

I've discovered that I can set defaults for columns on a postgres database in a django project using migrations.RunSQL('some sql').
I'm currently doing this by adding a column, makemigrations, then removing the column, makemigrations, and then manually modifying the migration file that is produced.
I tried copying an old migration file and then removing the old code so just the new sql could be run and got some strange errors.
CommandError: Conflicting migrations detected; multiple leaf nodes in the migration graph: (0067_auto_20180509_2327, 0068_auto_20180514_0707 in csmu).
To fix them run python manage.py makemigrations --merge
How would you create a 'manual' django migration?

You can create a manual migration by running the command:
python manage.py makemigrations app_name --name migration_name --empty
Where app_name corresponds to the app within your project you want to add the migration. Remember Django manages both Project and Apps (A project is a collection of configuration and apps for a particular website. A project can contain multiple apps. An app can be in multiple projects.)
And --empty flag is to create a migration file where you will have to add your manual migrations.
For example, on a project where you have an app named api that only has one migration file 0001_initial.py running:
python manage.py makemigrations api --name migration_example --empty
will create a file named 0002_migration_example.py under the directory api/migrations/ that will look like:
# Generated by Django 2.2.10 on 2020-05-26 20:37
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('api', '0001_initial'),
]
operations = [
]
And you should add migrations.RunSQL('some sql'). inside operations brackets, like:
operations = [
migrations.RunSQL('some sql')
]

You can learn how to make migrations by investigating the automatically generated migrations, for example:
class Migration(migrations.Migration):
dependencies = [
('app_details', '0001_initial'),
]
operations = [
migrations.AddField(
...,
),
migrations.CreateModel(
...,
),
migrations.RenameModel(
...,
),
migrations.RenameField(
...,
),
migrations.RemoveModel(
...,
),
# and so on
]
Create a manual migration file
use this command in the terminal: python manage.py makemigrations --empty.
Then add what you want in it.
notice: you have to compose between the "models.py" and the manual migrations.

Related

How to run a migration for a specific app in Django

What I need
I added an new app in my project and a separate database for it. I have created the Models for that app and now I need to migrate this models in this separate database
app name - authors_app
database name - authors
My code
python3 manage.py makemigrations authors_app
It creates the 0001_initial.py file which contains only models from my authors_app. So this step is OK
python3 manage.py migrate authors_app 0001_initial --database=authors
And this command runs not only my migrations from authors_app, but also migrations from my other app
Problem
I need to migrate only migrations from authors_app. But the migrate command runs the migrations from all apps. I have 58 migrations in my other app. And this command runs them all into the new database ...
Question
How can I run migrate for only authors_app
Update
Inside my authors_app Models I use one model from another app
from tibrains_app.models import Language
class AuthorLanguage(models.Model):
author = models.OneToOneField(Author, on_delete=models.CASCADE)
native_list = models.ManyToManyField(Language, related_name='author_native_languages')
all_list = models.ManyToManyField(Language, related_name='author_all_languages')
writing_list = models.ManyToManyField(Language, related_name='author_writing_languages')
And inside my 0001_initial file I have a dependencies
dependencies = [
('tibrains_app', '0058_book_history_period'),
]
Could this cause the problem?

Django database migration not working, new table not created

I initially created a database in mysql and used inspectdb to create all the models. So far so good, but then I started trying to make changes to the models and migrating them. I added columns to no avail, there were no changes in the database even though the migrations folder showed the changes. I began to wonder if it was something to do with case, so I tried again with a second model TestTwoT with table name and all fields in lower case. I then ran the make migrations which produced this output:
Migrations for 'testdb':
testdb/migrations/0010_testtwot.py
- Create model TestTwoT
The generated .py file in the migrations folder (which looks fine to me):
# Generated by Django 3.0.1 on 2020-02-10 22:46
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('testdb', '0009_auto_20200210_2241'),
]
operations = [
migrations.CreateModel(
name='TestTwoT',
fields=[
('id', models.AutoField(db_column='id', primary_key=True, serialize=False)),
('name', models.CharField(blank=True, db_column='name', max_length=1000, null=True)),
],
options={
'db_table': 'test_two_t',
'managed': True,
},
),
]
I then ran the migrate script which produced this output suggesting there were no problems creating the table:
Operations to perform:
Apply all migrations: admin, auth, contenttypes, testdb, sessions
Running migrations:
Applying testdb.0010_testtwot... OK
However, still no sign of my new table when I run the 'show tables' sql command or the 'describe test_two_t' command.
There is another complication in my scenario in that I am not using the default database, but my setup seems entirely OK and my application is working fine pointing to the database.
EDIT : Following Borut's advice I changed the commands to (adding the --database parameter):
python3 manage.py makemigrations
python3 manage.py migrate --database=testdb
EDIT2 : It's all working perfectly now (after I also deleted all the previous migration .py files and started from scratch with the corrected above commands).
Following Borut's advice I changed the commands to (adding the --database parameter):
python3 manage.py makemigrations
python3 manage.py migrate --database=testdb
It's all working perfectly now (after I also deleted all the previous migration .py files and started from scratch with the corrected above commands).

Django finding non-existent changes to a model after each migration

After running python manage.py migrate, Django will consistently return:
Running migrations:
No migrations to apply.
Your models have changes that are not yet reflected in a migration, and so won't be applied.
Run 'manage.py makemigrations' to make new migrations, and then re-run 'manage.py migrate' to apply them.
Hmm that's funny, I don't remember making a change.
python manage.py makemigrations --dry-run --verbosity=3
Generated by Django 1.11 on 2017-0x-xx xx:xx
from __future__ import unicode_literals
from django.db import migrations, models
import django_cryptography.fields
class Migration(migrations.Migration):
dependencies = [
('myApp', '0019_auto_xxxxxxx_xx'),
]
operations = [
migrations.AlterField(
model_name='myModel',
name='encrypted_field',
field=django_cryptography.fields.encrypt(models.CharField(verbose_name=models.CharField(verbose_name=models.CharField(max_length=50, verbose_name='Encrypted Field')))),
),
migrations.AlterField(
model_name='myModel',
name='second_encrypted_field',
field=django_cryptography.fields.encrypt(models.CharField(verbose_name=models.CharField(verbose_name=models.CharField(max_length=50, verbose_name='Second encrypted field')))),
),
]
That would be fine, but the exact same AlterField() was run in 0018_auto. I've tested it out on a couple systems, even tried making these migrations for real and applying but, but the warning keeps coming back in 0020_auto.
myModel.__str__ does reference one of those encrypted fields, which I think is what's causing the recursion in the migration. Still, I can't understand why that would make Django keep picking them up.
Any idea what could be causing this? Is it a bug? Something having to do with the nature of django_cryptography? Something else?

Django-migrations in Django 1.7 detects model changes but does not apply them on migrate

I have been trying to synchronize changes to a model in a Django app using migrations in 1.7 (postgres 9.1 - let me know if you need more details of my environment), but manage.py migrate doesn't seem to do anything, and sqlmigrate doesn't emit any SQL.
I thought Django 1.7 - "No migrations to apply" when run migrate after makemigrations might be applicable to my situation, and I did find some history in the django_migrations table in my database. I deleted the records for the app I am trying to migrate.
Recently I gave up on getting the alter table statements to generate/run and dropped the original version of the table. And while manage.py migrate states it is applying the migration, nothing happens to the database.
Here are the steps I've been trying:
Delete the history.
rm -r myapp/migrations
../manage.py dbshell
myapp_db=> delete from django_migrations where app='myapp'
Create an initial migration.
cp myapp/models.py.orig myapp/models.py
../manage.py makemigrations myapp
../manage.py migrate
manage.py migrate returns the following:
....
Running migrations:
Applying myapp.0001_initial... FAKED
Then I swap in the new models and generate a new migration.
cp myapp/models.py.new myapp/models.py
../manage.py makemigrations myapp
The result of makemigrations is in myapp/migrations/0002_notificationlog.py:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('myapp', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='NotificationLog',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('tstamp', models.DateTimeField(help_text=b'Log time', auto_now_add=True)),
('recipient', models.CharField(max_length=100)),
('subject', models.TextField()),
],
options={
},
bases=(models.Model,),
),
]
Run this migration:
../manage.py migrate
manage.py migrate acts like everything is OK:
....
Running migrations:
Applying myapp.0002_notificationlog... OK
I can see the log entries appear in django_migrations, but the table is not created.
I'm lost. Any idea what to try next?
Update
When running migrate -v 3 as requested, I see
Running pre-migrate handlers for application auth
followed by a similar line for each installed app.
Then
Loading 'initial_data' fixtures...
Checking '/var/www/environment/default/myproj/myproj' for fixtures...
No fixture 'initial_data' in '/var/www/environment/default/myproj/myproj'.
repeated a total of 13 times, the number of unmanaged apps.
Then
Running migrations:
Applying myapp.0001_initial... FAKED
followed by
Running post-migrate handlers for application auth
with a similar line for each installed app.
For migration 0002, the output is the same, except for
Running migrations:
Applying myapp.0002_notificationlog... OK
Note also that sqlmigrate doesn't output anything either:
../manage.py sqlmigrate myapp 0002 -v 3
Produces nothing at all.
Update 2
I copied myapp into a new project and was able to run migrations on it, but migrations stopped working when I imported my main project settings. Are there settings I should be aware of that could affect migration execution, particularly if I've been using South with previous versions of Django?
The problem disappeared with generic project settings and reappeared with my old, complex project settings. I tracked the problem down to a database Router class that was missing an allow_migrate method.
DATABASE_ROUTERS = [ 'myproj.routers.DatabaseAppsRouter', ]
I use this router to handle queries for a separate app in the project (readonly/MySQL).
Sadly I can't blame anyone but myself, since the Django documentation states clearly:
Note that migrations will just silently not perform any operations on a model for which [allow_migrate] returns False. (link)
I had created this router some time ago and didn't add the allow_migrate method to my router class when I upgraded to Django 1.7. When I added the method and made sure it returned True when needed, migrations run and the problem is solved.

django 1.7 migrate gets error "table already exists"

I am trying to apply a migration but am getting the error:
django.db.utils.OperationalError: (1050, "Table 'customers_customer'
already exists")
I get this by issuing the following command:
python manage.py migrate
My customer table already exists, so what do I do to let the migration know this, not error out, and run my modification to my model?
I ran this on my local environment with local database with no problem. It is when I pointed my database to production and ran migrate above that I get this error.
If you have the table created in the database, you can run
python manage.py migrate --fake <appname>
Mark migrations as run without actually running them
Or if you want to avoid some actions in your migration, you can edit the migration file under the app/migrations directory and comment the operations you don't want to do in the migrate execution.
Docs: https://docs.djangoproject.com/en/1.8/topics/migrations/#upgrading-from-south
or python manage.py help migrate
Its actually python manage.py migrate --fake <appname>
We can solve this issue in two way as mentioned in answer:
1.) By editing in migration file
We have migrations folder created in each application we create, In
those migration folder the migration file(0001_initial.py is the
initially created and after this all other files dependent on this
initial file will be create), When we run the python manage.py
migrate, For every APP the migration file will apply if there is
change in the file. We can see this run Applying on terminal after the
migrate command. If there is any issue in migration file we use to get
the error at that point. In my/our case:
Applying ValetUser.0002_keyroundslots_systemparameters_vehicleparking_vehicleparkingdetails...Traceback (most recent call last):
sqlite3.OperationalError: table "valet_keyroundslots" already exists
Here we can notice that the file in which we have issue is mentioned
i.e ValetUser.0002_keyroundslots_systemparameters, So we can Go to the
App and then migrations and in 0002 file we can Comment the
CreateModel Operation of That particular Model in which we are facing issue while
applying migrations.
example:
operations = [
# migrations.CreateModel(
# name='KeyRoundSlots',
# fields=[
# ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
# ('key_round', models.IntegerField()),
# ('key_slot', models.IntegerField()),
# ('is_available', models.BooleanField()),
# ('Valet_id', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='valet_location', to='ValetUser.ValetAt')),
# ],
# options={
# 'db_table': 'valet_keyroundslots',
# },
# ),
2.) By applying fake migration of the modified migration file of the particular APP in which we are facing the error/issue, --fake will
apply the fake migration that will not effect to the already applied
migration of the model.
python manage.py migrate --fake <appname>
The answers given Waqas and elmonkeylp are also right, I just wanna
explain it in brief with the help of we use to scenario