Django - view sql query without publishing migrations - django

When I make changes to some models, I want to view the SQL the django would be running to implement those changes on the DB.
The normal way of doing this would be to do 'makemigrations appname'. This will generate a migration, let's say, - '0001_someName.py'. Then one can do 'sqlmigrate 0001_someName.py'
But I want to view the sql directly, without having to create that intermediate migration. Can this be done?

Use the sqlmigrate command from manage.py.
python manage.py sqlmigrate <appname> <migration number eg. 0001 or 0004>
will display the SQL statements for a specific migration of the app.

Django does not provide that option. You can always create the migration, run sqlmigrate, and delete the migration file. As long as it isn't applied with migrate, nothing will happen.

These existing answers are not enough, as I found out trying to follow them. First detect and make the migration script for your app:
manage.py makemigrations app
Make note of the four-digit migration number which starts the filename. Then print the SQL with:
manage.py sqlmigrate app 0002 # <-- number here
When finished, remove the file before it gets run or committed:
rm api/migrations/0002_auto_8675309.py

Run
python manage.py sql <appname>
-- Prints the CREATE TABLE SQL statements for the given app name(s).
python manage.py sqlall <appname>
-- Prints the CREATE TABLE and initial-data SQL statements for the given app name(s).
You'll find detail documentation here.
https://docs.djangoproject.com/en/1.8/ref/django-admin/

Related

Django's --fake-initial doesn't work when migrating with existing tables

I am migrating a project from Django 1.1 to Django 3.0 I am done with the project. When I am dumping the production dump to my local in the newly converted project I get "Table already exists".
Here's what I am doing.
mysql> create database xyx;
docker exec -i <container-hash> mysql -u<user> -p<password> xyx < dbdump.sql
then I run the migrate, as I have had to do some changes to the previously given models.
./manage.py migrate --fake-initial
this is the output I get
_mysql.connection.query(self, query)
django.db.utils.OperationalError: (1050, "Table 'city' already exists")
So, what to do ?
Alright boys and girls, here's the approach I followed to solve this problem.
I dumped the entire database.
docker exec -i <container-hash> mysql -u<username> -p<password> <dbname> < dump.sql
Now I listed all the migrations I made using
./manage.py showmigrations <app-name>
This will give me the list of all the migrations I have applied, now from inspecting the migrations, I realized that from the 7th migration to the 30th migration I had done my changes.
Here's the tedious part which any sys admin can write a script to do in less than 4 lines of bash script. You can generate the raw SQL of any migration with this command.
./manage.py sqlmigrate <app-name> <migration-name> > changes-i-made.sql
Now that I have created my changes-i-made.sql file I'll need to run this script 22 more times but with >> otherwise everytime you run the command with a single > it will keep overwriting your changes file.
Now once all of your migration changes are recorded inside a file, open up your sql shell connect to the database and start pasting the changes or do some sql magic to pick all the changes directly from the file.
Once you're done go ahead and fake all the migrations, cause you don't need Django to do them you already did.
./manage.py migrate --fake
and then login to your production instance and get ready to fuck with your senior team lead who said you couldn't do it.
I just checked to see if this approach is working and the future migrations will be working, so I created one and everything works like a breeze.

Django Programming error column does not exist even after running migrations

I run python manage.py makemigrations and I get:
No changes detected
Then, python manage.py migrate and I get:
No migrations to apply.
Then, I try to push the changes to production:
git push heroku master
Everything up-to-date
Then, in production, I repeat the command:
heroku run python manage.py migrate
No migrations to apply.
Just in case, I run makemigrations in production:
heroku run python manage.py makemigrations
No changes detected
WHY then I get a
ProgrammingError at ....
column .... does not exist
"No changes detected" means the database is coherent with the code.
How can I debug this?¡?
I got the same problem (column not exist) but when I try to run migrate not with makemigrations (it is the same issue I believe)
Cause: I removed the migration files and replaced them with single pretending intial migration file 0001 before running the migration for the last change
Solution:
Drop tables involved in that migration of that app (consider a backup workaround if any)
Delete the rows responsible of the migration of that app from the table django_migrations in which migrations are recorded, This is how Django knows which migrations have been applied and which still need to be applied.
And here is how solve this problem:
log in as postgres user (my user is called posgres):
sudo -i -u postgres
Open an sql terminal and connect to your database:
psql -d database_name
List your table and spot the tables related to that app:
\dt
Drop them (consider drop order with relations):
DROP TABLE tablename ;
List migration record, you will see migrations applied classified like so:
id | app | name | applied
--+------+--------+---------+
SELECT * FROM django_migrations;
Delete rows of migrations of that app (you can delete by id or by app, with app don't forget 'quotes'):
DELETE FROM django_migrations WHERE app='yourapp';
log out and run your migrations merely (maybe run makemigrations in your case):
python manage.py migrate --settings=your.settings.module_if_any
Note: it is possible that in your case will not have to drop all the tables of that app and not all the migrations, just the ones of the models causing the problem.
I wish this can help.
Django migrations are recorded in your database under the 'django_migrations' table. This is how Django knows which migrations have been applied and which still need to be applied.
Have a look at django_migrations table in your DB. It may be that something went wrong when your migration was applied. So, delete the row in the table which has the migration file name that is related to that column that 'does not exist'. Then, try to re-run a migration.
Here's what i tried and it worked:
Go and add manually the column to your table
run python manage.py makemigrations
go back drop that column you added
run python manage.py migrate
I had a similar issue - the error message appeared when I clicked on the model on the django-admin site. I solved it by commenting out the field in models.py, then running migrations. Following this I uncommented the field and re ran the migrations. After that the error message disappeared.
My case might be a bit obscure, but if it helps someone, it is worth documenting here.
I was calling a function in one of my migrations, which imported a Model of said migration regularly, i.e.
from myApp.models import ModelX
The only way models should be imported in migrations would be using e.g. RunPython:
def myFunc(apps, schema_editor):
MyModel = apps.get_model('myApp 'MyModel')
and then calling that function like so:
class Migration(migrations.Migration):
operations = [
migrations.RunPython(initialize_mhs, reverse_code=migrations.RunPython.noop),
]
Additionally the original import worked until I modified the model in a later migration, making this error harder to locate.
So, I always run into this sort of problem, so today I decided to try and work it out at the database level. Thing is, I changed a model field name which Django didn't bother reflecting in a migration file. I only found out later when I ran into problems. I later looked at the migration files and discovered there was no migration for that change. But I didn't notice because I made other changes as well, so once I saw a migration file I was happy.
My advice. Create migration for each change one at a time. That way you get to see if it happened or not.
So here's my working through it in MySQL.
open mysql console.
show databases; # see all my dbs. I deleted a few
drop database <db-name>; # if needed
use <db-name>; # the database name for your django project
show tables; # see all tables in the database
DESCRIBE <table-name>; # shows columns in the database
SHOW COLUMNS FROM <db-name>; # same thing as above
ALTER TABLE <table-name> CHANGE <old-column-name> <new-column-name> <col-type>; # now I manually updated my column name
If you're using postgresql, just google the corresponding commands.
The issue was in the Models for me, for some reason Django was adding '_id' to the end of my Foreign Key column. I had to explicitly set the related named to the Foreign Key. Here 'Cards' is the parent table and 'Prices' is the child table.
class Cards(models.Model):
unique_id = models.CharField(primary_key=True, max_length=45)
name = models.CharField(max_length=225)
class Prices(models.Model):
unique_id = models.ForeignKey(Cards, models.DO_NOTHING)
Works after changing to:
class Cards(models.Model):
unique_id = models.CharField(primary_key=True, max_length=45)
name = models.CharField(max_length=225)
class Prices(models.Model):
unique_id = models.ForeignKey(Cards, models.DO_NOTHING, db_column='unique_id')
When I get this error, my extreme way to solve it is to reset my database:
Reset your database
For Postgresql on Heroku:
Heroku > your_app > Resources > database > add-ons > click on your database and open it
For postgresql
settings > Reset database
Delete all files in your_app > migrations > __pycache__ except __init.py__
Delete all files in your_app > migrations except __pycache__ folder and __init.py__
Then run:
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
type in to create your superuser, then run:
python manage.py makemigrations
python manage.py migrate
python manage.py
If you are able to inspect your models from your admin section, then it should be all okay now.
Just remove corresponding row migrations for that model in 'django_migrations' model in database.
And re run python manage.py migrate app_name
I tried all these answers with not much luck! What I did to have this problem solved with no harm was to go back through the migration files and find where the actual model was being created for the first time then manually add the field (in the column not being existed error message). Until if you run makemigrations --dry-run you get/see "No changes detected" and that worked. Basically, in my case, I had to carefully take my desired db changes back in time in proper migration file, rather creating a new migration now at the end of migration dependency chain.
Open the latest py file created after running the makemigrations command inside migrations folder of that particular app.
Inside class Migration there is a list attribute called 'operations'.
Remove the particular elements migrations.RemoveField(...).
Save and run python manage.py migrate.
A easier solution to the problem is to make your models exactly like it is in the migration first. and run python manage.py migrate.
Then revert those changes
Run
python manage.py makemigrations
python manage.py migrate
To check for which migrations are applied and which are not, use -:
python manage.py showmigrations
I solved a similar problem by deleting all migrations files (Don't forget to make a backup) and python manage.py makemigrations all of them into one clean file in development and pulling new files on the server. Before then I had dropped existing tables on the PostgreSQL.
I was getting this error for some reason when Django was looking for a column of type ForeignKey named category_id when the actual name in the database was category. I tried every Django solution I could imagine (renaming field, explicitly setting column name, etc.). I didn't want to drop tables or rows as this was a production database. The solution was simply to rename the column manually using SQL. In my case:
ALTER TABLE table_name
RENAME COLUMN category TO category_id;
Make sure you backup your database, ensure this won't break any other applications consuming that particular table, and consider having a fallback column if necessary.
What helped me in the end was simply dropping the database and creating it again as well as deleting all migrations files (including cache). (only removing migrations file didn't work for me at all)
sudo su - postgres
psql
DROP DATABASE 'yourdatabase';
CREATE DATABASE 'yourdatabase';
GRANT ALL PRIVILEGES ON DATABASE 'yourdatabase' to 'yourdjangouser';
then just
python manage.py makemigrations
python manage.py migrate
python manage.py runserver
If you're in development and you make some examples of data that's not important, this step is beneficial for me: just flush your data, make migrations, and migrate:
python manage.py flush
python manage.py makemigrations
python manage.py migrate
After that, you may create a new database from scratch, I hope this information was helpful.
Solved this issue by running
python manage.py migrate
in Heroku Bash shell

Django Migration is not applying the migration changes

Using django 1.7.7 I want to use django's migration to add or remove a field.
so I modified model.py and ran
python manage.py makemigrations myproj
Migrations for 'myproj':
0001_initial.py:
- Create model Interp
- Create model InterpVersion
python manage.py migrate myproj
Operations to perform:
Apply all migrations: myproj
Running migrations:
Applying myproj.0001_initial... FAKED
python manage.py runserver
Then checked the admin page, it is not updated.
Then I tried removing the migration folder and tried again; the migrate command says there are no migrations to apply.
How can I do the migration?
Note: I want to use the new technique using django's migration not the old south approach.
Make sure that the migrations/ folder contains a __init__.py file
Lost half an hour over that.
Deleting the migration directory is never a good idea, because Django then loses track of which migration has been applied and which not (and once an app is deployed somewhere it can become quite difficult to get things back in sync).
Disclaimer: whenever things like that occur it is best to backup the database if it contains anything valuable. If in early development it is not necessary, but once things on the backend get out of sync there is a chance of things getting worse. :-)
To recover, you could try resetting your models to match exactly what they were before you have added/removed the fields. Then you can run
$ python manage.py makemigrations myproj
which will lead to an initial migration (0001_initial...). Then you can tell Django to fake that migration, which means to tell it to set its internal counter to this 0001_initial:
With Django 1.7:
$ python manage.py migrate myproj
With Django >= 1.8:
$ python manage.py migrate myproj --fake-initial
Now, try to change your model and run makemigrations again. It should now create a 0002_foobar migration that you could run as expected.
In my case, the migrations were not being reflected in mysql database. I manually removed the row of 'myapp'(in your case 'myproj') from the table 'django_migrations' in mysql database and ran the same commands again for migration.
Most of the above solutions would help in the issue, however, I wanted to point out another possible (albeit rare) possibility that the allow_migrate method of database router may be returning False when it should have returned None.
Django has a setting DATABASE_ROUTERS which will be used to determine which database to use when performing a database query.
From the docs:
if you want to implement more interesting database allocation behaviors, you can define and install your own database routers.
A database router class implements up to four methods:
db_for_read(model, **hints)
db_for_write(model, **hints)
allow_relation(obj1, obj2, **hints)
allow_migrate(db, app_label, model_name=None, **hints)
From the documentation:
allow_migrate(db, app_label, model_name=None, **hints)
Determine if the migration operation is allowed to run on the database with alias db. Return True if the operation should run, False if it shouldn’t run, or None if the router has no opinion.
It is possible that one of the database routers in sequence is returning False for the migration that you're trying to run, in which case the particular operation will not be run.
I find Django migrations a bit of a mystery, and tend to prefer external tools (liquibase, for example).
However, I just ran into this "No migrations to apply" problem as well. I also tried removing the migrations folder, which doesn't help.
If you've already removed the migrations folder, here's an approach that worked for me.
First, generate the new "clean" migrations:
$ python manage.py makemigrations foo
Migrations for 'foo':
dashboard/foo/migrations/0001_initial.py
- Create model Foo
- Create model Bar
Then look at the SQL and see if it looks reasonable:
$ python manage.py sqlmigrate foo 0001
BEGIN;
--
-- Create model Foo
--
CREATE TABLE "foo" ("id" serial NOT NULL PRIMARY KEY, ... "created_at" timestamp with time zone NOT NULL, "updated_at" timestamp with time zone NOT NULL);
CREATE INDEX "..." ON "foo" (...);
COMMIT;
Then apply execute that same SQL on your database.
I'm using Postgres but it will be similar for other engines.
One way is to write the content to a file:
$ python manage.py sqlmigrate foo 0001 > foo.sql
$ psql dbname username < foo.sql
BEGIN
CREATE TABLE
CREATE INDEX
COMMIT
Another is pipe the SQL directly:
$ python manage.py sqlmigrate foo 0001 | psql dbname username
Or copy and paste it, etc.
pip install django-extensions
and add this in the install app of settings.py
INSTALLED_APPS = [
'django_extensions'
]
Then run
python ./manage.py reset_db
Then run migrations again
python manage.py makemigrations
python manage.py migrate
Now, run migrations for your installed apps
python manage.py makemigrations your_app_name
python manage.py migrtate your_app_name
Done! See Your Database...
In addition to the other answers, make sure that in models.py, you have managed = True in each table's meta
You can remove your db
python manage.py makemigrations
python manage.py migrate
python manage.py migrate --run-syncdb
and see your data base this is working :)
Similar to Andrew E above but with a few changes especially where you haven't deleted the migrations folder in your quest to resolve the issue
1 - In your intact migration folder just examine the 000*.py files counting from the highest down to initial.py till you find the one where your Model is defined, say 0002_entry.py
2 - python manage.py sqlmigrate app-name 0002 > 0002_sql.txt to capture the SQL commands
3 - Edit this file to ensure there are no hard CR/LFs and the ALTER, CREATE INDEX commands are each on own single line
4 - Log into your DB (I have Postgres) and run these commands
In Database delete row myproj from the table django_migrations.
Delete all migration files in the migrations folder.
Then run python manage.py makemigrations and python manage.py migrate commands.

Django 1.8 - what's the difference between migrate and makemigrations?

According to the documentation here:
https://docs.djangoproject.com/en/1.8/topics/migrations/ it says:
migrate, which is responsible for applying migrations, as well as unapplying and listing their status.
and
makemigrations, which is responsible for creating new migrations based on the changes you have made to your models.
From what I understand, I first do
makemigrations
to create the migration file and then do
migrate
to actually apply the migration?
Do note though that I just began my Django project and I added my app to my "installed_apps" list. After that, I did
python manage.py runserver
and it said
You have unapplied migrations; your app may not work properly until they are applied. Run 'python manage.py migrate' to apply them.
It didn't mention anything about running makemigrations.
According the Polls tutorial:
python manage.py makemigrations <app>: Create the migrations (generate the SQL commands).
python manage.py migrate: Run the migrations (execute the SQL commands).
As Django's documentation says Migrations are Django’s way of propagating changes you make to your models (adding a field, deleting a model, etc.) into your database schema.
makemigrations basically generates the SQL commands for preinstalled apps (which can be viewed in installed apps in settings.py) and your newly created apps' model which you add in installed apps.It does not execute those commands in your database file. So tables doesn't created after makemigrations.
After applying makemigrations you can see those SQL commands with sqlmigrate which shows all the SQL commands which has been generated by makemigrations.
migrate executes those SQL commands in database file.So after executing migrate all the tables of your installed apps are created in your database file.
You can conform this by installing sqlite browser and opening db.sqlite3 you can see all the tables appears in the database file after executing migrate command.
As we know Django is an ORM (Object Relational Mapping). When we use the command:
python manage.py makemigrations [app_name]
It will generate the sql command to create the table corresponding to each class you made in models.py file.
then the command:
python manage.py migrate [app_name]
will create the table in database using the commands which have been generated by makemigrations.
For example, if we make a model class-
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
The corresponding sql command after using makemigrations will be
CREATE TABLE myapp_person (
"id" serial NOT NULL PRIMARY KEY,
"first_name" varchar(30) NOT NULL,
"last_name" varchar(30) NOT NULL
);
and using above command, table will be created in the database when we use migrate.
You should run the command -migrate- after adding a new app under the INSTALLED APPS section in the settings.py file in order to synchronize the database state with your current set of models. Assuming you've already modified the models.py file.
When you run -makemigrations- it packages up changes to your model into individual migration files.
Normally you would first run makemigrations and then migrate.
See documentation on Django Models
It is necessary to run both the commands to complete the migration of the database tables to be in sync with your models.
makemigrations simply analyzes your current models for any changes that would be out of sync with your database and creates a migrations file that can be used to bring the in sync. If left at this point, your models would still be out of sync with your database possibly breaking your code that queries the database.
migrate is the command to "Make It So!" and apply the changes noted during the makemigrations phase.
Source
This is django's replacement for the old manual south way of making migrations, they can be used to catalog changes in your models and write out changes that will take place in the db.
Migrate is basically the old syncdb but it takes into account all the migrations made by makemigrations.
makemigrations: creates the migrations (generating SQL Command- not yet executed)
migrate: run the migrations (executes the SQL command)
But in your case, Django is asking you to migrate the DEFAULT migrations which should run before first running of server. This would have been the same warning without even creating the first app.
Make migrations : Basically it generate SQL Commands for preinstalled apps and newly created app model which you added in installed app. It dose not executed SQL commands in your database. So actual tables are not created in DB.
Migrate : Migrate execute those SQL commands which are generated by make-migration in Database file . So after migrate all the tables of installed app are created in DB.
According to the second tutorial of the django tutorial series. Migrations are:
The migrate command takes all the migrations that haven’t been applied (Django tracks which ones are applied using a special table in your database called django_migrations) and runs them against your database - essentially, synchronizing the changes you made to your models with the schema in the database.
So pretty much all it does is:
When you execute the make migrations command you're saving the 'instructions' to mysql
When you execute the migrate command, you're executing those same instructions

Why does running sqlclear and syncdb not drop sqlite3 tables

I want to drop some tables I created for the polls app from the Django tutorials. I am using Django 1.6.5.
I start by turning off the server and then running
manage.py sqlclear
This prints out
BEGIN;
DROP TABLE "polls_choice";
DROP TABLE "polls_poll";
COMMIT;
I then run
manage.py syncdb
When I start the server, go to the admin panel, and click on the models, the values are all still there. Why is this happening? It seems like if I'm dropping those tables, at the very least any existing values should be gone.
According to the documentation, the manage.py sqlclear command only prints queries to execute to clear the database. You need to execute them by yourself.
You can also use manage.py flush to get the empty database (read carefully the documentation, it is actually executing some handlers and adding initial fixtures if you have any)
django-admin.py sqlclear
Prints the DROP TABLE SQL statements for the given app name(s).
The --database option can be used to specify the database for which to print the SQL.
you need to enter here:
python manage.py dbshell
and paste what sqlclear printed out