New Django app initial DB migrations of an existing database - python

I have an existing database filled with a bunch of data. I want to migrate to Django so I went ahead and created the necessary models with python manage.py inspectdb. I haven't changed anything besides removed the managed = False since I want Django to manage the tables (mistake perhaps for initial migration?).
So now that the models are ready, how can I generate the first migration file so that I can start changing the fields to generate additional migrations (renaming a field here and there). I understand python manage.py migrate will handle the creation of Django-specific models but does not actually create any migration files? Some sources indicate the first migration file should be run with --fake so it's not applied. Will the next migration files remember to run the first one as fake and only apply the next ones?

You want makemigrations to create the migrations. The migrate command applies migrations, it does not create them.
You can use the --fake-initial option so that Django does not try to create the tables that already exist. Note that --fake and --fake-initial are two different commands.
When you run migrate, the django_migrations table is updated to store the currently applied migrations. The migration files themselves are not changed. The --fake command updates the django_migrations table without running the migration. That means that if you use it incorrectly your database and django_migrations table can get out of sync, which can be difficult to fix.

Related

How could I rework Django migrations without affecting database? [duplicate]

I changed a field on a model class (which has no classes point to it, only one foreign key pointing out of it). Somehow, this stuffed up my migrations and it keeps saying "django.db.migrations.graph.NodeNotFoundError:" looking for migration files that do not exist.
I accidentally deleted several files in my 'migrations' folder.
My database contains a lot of data, and I do not want to break it.
Will I lose any data if I:
Remove the table that caused the problem in the first place (psql, \d, DROP TABLE tablename)
delete all my migration files
Re run the migration from the start?
./manage.py makemigrations
./manage.py migrate
Can anyone recommend another way of fixing this?
Here is the traceback:
http://dpaste.com/0Y1YDXS
Aren't you using git so that you can get your migration files back? If not, install and use it, starting now
I would suggest:
make a backup/dump of your database first, in case something goes wrong
Delete all migrations
Empty migration table in psql
call makemigrations
call migrate --fake-initial
Empty the django_migrations table:
delete from django_migrations;
Remove all the files in migrations folders in each and every app of your project.
Reset the migrations for the "built-in" apps:
python manage.py migrate --fake
Create initial migrations for each and every app:
python manage.py makemigrations your_app_name
Final step is to create fake initial migrations:
python manage.py migrate --fake-initial
See here https://micropyramid.com/blog/how-to-create-initial-django-migrations-for-existing-schema/

Django - can't update model in database

I have a table in my database (postgresql) that is associated with a model called feedback in my Django app (which is also called feedback).
I deleted a couple of columns of the feedback model in the models.py file and then created a migration using:
python manage.py makemigrations feedback
And then tried to "merge" it with my database using:
python manage.py migrate feedback
But i got the error:
django.db.utils.ProgrammingError: relation "feedback" already exists
Of course it exists, but i want to apply the changes i've made. In the migrations folder i have the following files:
__init__.py
0001_initial.py
0002_remove_feedback_created_on.py
0003_remove_feedback_is_read.py
The last one contains my most recent changes. What should i do?
Usually this relation x already exists problem appears when you've applied the change at some point in the database, but the Django migrations system hasn't got a clue about the fact that you already did that. How could it happen? For example if you add a ForeignKey field to your model, make a migration, migrate it, but then change your mind and delete the migration without migrating backwards before that. Nothing breaks in the project, but the relationship and the field in the database remain (you might run into trouble, if the field is non-nullable). Now if you change your mind again and decide that shiiit, I needed that field anyhows and add it again, make a new migration and try to migrate it, then you get the relation x already exists error.
Ok, what then? Usually the simplest way is to fake the failing migration, but BEWARE that if you have any other unapplied changes in the migrations, then those won't be applied to the database either. Before you start faking migrations, make sure that you understand what and why you are faking. Ideally you'd have only one AddField in the migration file that is soon to be faked, because otherwise all changes in the migration file will be faked (faking migrations means, that the changes are not applied to database, but Django will consider them done).
If you have two unapplied migrations, then you definitely shouldn't run migrate --fake without specifying the migration number, because then the latter unapplied migration will be unapplied as well. It SEEMS in your case, that running manage.py migrate 0002 --fake and manage.py migrate afterwards might fix everything, but without knowing everything about what you've done, it's impossible to say for certain.
If I picked up your project, here's what I would do:
1) Check if 0002 contains more than one change.
If yes, then copy everything except the failing field to 0003.
If no, then proceed to manage.py migrate 0002 --fake.
2) Run manage.py migrate again to migrate 0003.
It could also help in the case of migrations.
python3 manage.py migrate --run-syncdb

How to force migrations to a DB if some tables already exist in Django?

I have a Python/Django proyect. Due to some rolls back, and other mixed stuff we ended up in a kind of odd scenario.
The current scenario is like this:
DB has the correct tables
DB can't be rolled back or dropped
Code is up to date
Migrations folder is behind the DB by one or two migrations. (These migrations were applied from somewhere else and that "somewhere else" doesn't exist anymore)
I add and alter some models
I run makemigrations
New migrations are created, but it's a mix of new tables and some tables that already exist in the DB.
If I run migrate it will complain that some of the tables that I'm trying to create already exist.
What I need:
To be able to run the migrations and kind of "ignore" the existing tables and apply the new ones. Or any alternative way to achieve this.
Is that possible?
When you apply a migration, Django inserts a row in a table called django_migrations. That's the only way Django knows which migrations have been applied already and which have not. So the rows in that table have to match the files in your migrations directory. If you've lost the migration files after they were applied, or done anything else to get things out of sync, you'll have problems.. because the migration numbers in your database refer to different migration files than the ones in your project.
So before you do anything else, you need to bring things back into sync by deleting the django_migrations table rows for any migration files that you've lost somehow and can't get back. The table should contain rows for only those migrations that you do have and that were actually applied to the database correctly.
Now you need to deal with any changes in your database that Django Migrations doesn't know about.. and for that there are a few options:
If things worked out such that the database changes that were already applied to the database are in different migration files than the ones that weren't, then you can fix it by running your migrations one at a time using the --fake option on any changes that are in reality already in the database. The fake option just writes the row to the django_migrations table marking the migration as done. Only do this if the database does in fact already have all the changes contained in that migration file.
And those migration files that contain only changes which have not been applied to the database, run without the --fake option and Django will apply them. eg:
# database already has it
manage.py migrate myapp 0003 --fake
# need it
manage.py migrate myapp 0004
# database already has it
manage.py migrate myapp 0005 --fake
If you have migration files where some but not all of the changes have been applied, then you have a bigger problem. In that case, there are several ways to go about it (choose ONLY ONE):
Edit the migration files to put changes that have already been applied (whether Django did it or you did it manually does not matter) into lower number migrations, and put everything you need done into higher numbered files. Now you can --fake the lower number ones, and run the higher numbered ones as normal. Let's say you have 10 changes you made to your models, and 5 of those changes are actually in the database already, but Django doesn't know about them.. so when you run makemigrations, a new migration is created with all 10 changes. This will normally fail because the database server can't for example add a column that already exists. Move these already-applied changes out of your new migration file, into the previous (already applied) migration file. Django will then assume that these were applied with the previous migration and will not try to apply them again. You can then migrate as normal and the new changes will be applied.
If you don't want to touch your older migration file, a cleaner way to do this is to first run makemigrations --empty appname to create an empty migration file. Then run makemigrations which will create another migration with all the changes that Django thinks need to be done. Move the already done migrations from that file into the empty migration you created.. then --fake that one. This will put Django's understanding of what the database looks like will be in sync with reality and you can then migrate as normal, applying the changes in the last migration file.
Get rid of any new migrations you just created using makemigrations. Now, comment out or put back anything in your models that has not been applied to the database, leaving your code matching what's actually in the database. Now you can do makemigrations and migrate appname --fake and you will get things back in sync. Then uncomment your new code and run 'makemigrations' then migrate as normal and the changes will be applied. If the changes are small (for example, adding a few fields), sometimes this is easiest. If the changes are large, it isn't....
You can go ahead and (carefully) make the database changes yourself, bringing the database up to date. Now just run migrate --fake and if you didn't mess up then everything will be ok. Again, this is easy for smaller changes, not as easy for complicated ones.
You can run manage.py sqlmigrate > mychanges.sql. This generates mychanges.sql containing all the SQL Django WOULD have executed against the database. Now edit that file to remove any changes that have already been applied, leaving what needs to be done. Execute that SQL using pgadmin or psql (you're using postgresql I hope). Now the changes have all been made.. so you can run manage.py migrate --fake, this will bring Django into sync with reality and you should be all set. If your SQL skills are sufficient, this is probably the most straightforward solution.
I should add two warnings:
First, if you apply a later migration, eg 0003_foobar.py, and then things don't work out and you decide to try going back and apply 0002_bazbuz.py, then Django will TAKE STUFF OUT OF YOUR DATABASE. For example a column you might have added in 0003 will be dropped along with its data. Since you say you can't lose data, be very careful about going back.
Second, do not rush into running --fake migrations. Make sure that the entire migration you are about to fake is actually in the database already. Else it gets very confusing. If you do regret faking migrations and don't want to roll back, you can erase django's knowledge of the faked migration by deleting that row from the django_migrations table. It is ok to do this.. if you understand what you are doing. If you know that the migration really was not applied, then it's ok.
This blog post really nails it. https://simpleisbetterthancomplex.com/tutorial/2016/07/26/how-to-reset-migrations.html
Let me summarize the steps in his scenario 2 (you have a production database and want to change schema/models in one or more apps). In my case, I had two apps, queue and routingslip, that had model modifications that I needed to apply to a production system. Key was I already had the database, so this is where --fake-initial comes into play.
Here are the steps I followed. As always, backup everything before starting. I do work in a VM so I just took a snapshot before going forward.
1) Remove the migration history for each app.
python manage.py migrate --fake queue zero
python manage.py migrate --fake routingslip zero
2) Blow away any migration files in the entire project within which the app(s) reside.
find . -path "*/migrations/*.py" -not -name "__init__.py" -delete
find . -path "*/migrations/*.pyc" -delete
3) Make migrations
python manage.py makemigrations
4) Apply the migrations, faking initial because the database already exists and we just want the changes:
python manage.py migrate --fake-initial
Worked great for me.
If you don't have any migration files or you lost the previous file and want to migrate new changes, then you need to follow the following steps carefully:
# To create a new migration file before changing the models.
cmd: python manage.py makemigrations app_name
# Fake migrate
cmd: python manage.py migrate app_name 0005 --fake #[0005 is the migration file number created just now. It'll seem like 0005_add_address or something like this.]
# To create a new migration file after changing the models.
cmd: python manage.py makemigrations app_name
# database already has it
cmd: python manage.py migrate app_name 0006 #[0006 is the migration file number created just now.]

How do I re-create databases after they were deleted?

I used the python manage.py makemigrations myApp and python manage.py migrate myApp commands to create Postgres tables in my database. Then someone manually deleted them with SQL queries.
Can I re-create these tables, without data, using terminal commands?
It depends.
Did they delete all of the tables? If so thats easy. Just rerun the
manage.py migrate.
Did they only delete new tables that you have added with migrations?
Not so bad, go into the django_migrations table, and delete the entries for the migrations that created the deleted tables from that table and rerun
manage.py migrate.
When you run makemigrations, Django creates the migration file but doesn't do anything with it in terms of touching the database.
When you run the migrate command, Django runs the alter table commands on the database and adds an entry to the django_migrations table, so it knows which migrations have been done, and which still need to be run.
If the person has deleted a random set of tables that are out of sync with your migrations its going to be a mess and its going to involve a lot of manual work to make sure your migrations and database tables are in sync.

django 1.7 how to migration with existed tables

I upgrade to django 1.7
and need to deal with migration
My database already exists tables
Here is my step :
1.I delete the migration in django app test
2.I remove south(from INSTALLED APPS ) in django settings.py
3.run python manage.py makemigrations test
Migrations for 'test':
0001_initial.py:
- Create model Person
- Create model Book
- Create model Artical
run python manage.py migrate test
Operations to perform:
Apply all migrations: test
Running migrations:
Applying test.0001_initial... FAKED
is it right???
How to do migration if I already have tables?
Please guide me Thank you
it is right if the tables that exist in your database have the same structure as your current models (i.e. you haven't modified your models.py file after you applied you last migrations with South). If that's the case, you can proceed without worries.
If the structure is different, you can try different approaches:
Create the needed migrations manually. You will have to write your own migration with the needed modifications. Here you can find some example code of a migrations file for altering or adding fields and here you have the complete reference of the methods you can call
Modify your database manually with phpmyadmin, raw sql or the method you prefer.
Do a python manage.py dumpdata app1 app2 app3 > data.json, remove the db, create it again and to a python manage.py loaddata data.json. This may raise some errors because the data you saved was with the old structure, you will have to deal with each error.
Or the least preferred, if the data you had is not needed, just remove the db and recreate it.
There is nothing wrong with the way you are doing it.
The reason the first migration is faked is because your tables are already created:
Run python manage.py migrate. Django will see that the tables for the
initial migrations already exist and mark them as applied without
running them.
From the documentation on upgrading from South.

Categories

Resources