How do I merge a Django app? - python

I have two Django apps. A, the core app, and B, which started out as an individual app, but actually fits better within A as we later discovered. I'm able to move all the code from B into A, but falling short when it comes to the database.
B will be deleted, so it'd be best if the migration lived entirely in A. That way, anyone can pull the latest code and run manage.py migrate and it will work on local machines even after B is deleted.
However, the data still needs to be migrated from B to A when running the migration on the production database.
My attempts
I tried inlining B's models in the migration, querying them (if they exist), then saving new objects using the new models. This is a technique I've used with SQLAlchemy before. The only problem is that Django then adds these temporary models to django_contenttype and tells me "The following content types are stale and need to be deleted" the next time I run a migration. (I also don't know if Django does anything else I might have missed.)
I also tried setting db_table to the old app's database table as suggested here, but then the table doesn't exist when running locally from scratch. If I include a CreateModel migration, then I get django.db.utils.OperationalError: table "b_model" already exists when migrating on an existing database.
Any ideas?

Related

Freezing database for testing new features in Django

In my Django app, I want to add a couple of fields to my existing models and possibly create a new class. I just want to test the new feature and approve if it works.
I can revert the code using git easily. But if I make a makemigrations+migrate then my MySQL database will change and reversing the changes looks like manual deletion of tables and reverting to an old state using a command like django-admin migrate [app_label] [migration_name] (In some cases it looks really cumbersome, example).
I'm wondering if there is any safe practice to try manipulating the database and revert it back to it's initial state safely.
Probable solution #1:
You can utilize the test database that gets created when using django.test.TestCase:
Tests that require a database (namely, model tests) will not use your
“real” (production) database. Separate, blank databases are created
for the tests.
Create some unit tests for your project and make your migrations (without migrating to your production DB, just keep the migrations). Then:
If the database does not exist, it will first be created. Any
migrations will also be applied in order to keep it up to date.
Usually, the database gets destroyed at the end of your tests, but you can keep it between runs:
You can prevent the test databases from being destroyed by using them
test --keepdb option. This will preserve the test database between
runs.
With this trick you can test every migration you make in a fake DB and when you do finalize your model and you have all the migrations history complete, you can migrate on your production DB.
Probable solution #2:
You can make a copy of your database as #albar suggests and have it as a back up while you are working on your new migrations.
Break stuff as much as you want and when you are set and done, replace the "battered" DB with your back up and apply your migration history to it.

How to create a new table using model

So I have this django installation in which there are a bunch of migration scripts. They look like so:
00001_initial.py
00002_blah_blah.py
00003_bleh_bleh.py
Now I know these are "database building" scripts which will take stuff defined in models.py and run them against the db to "create" tables and stuff.
I want to create a new table(so I created its definition in models.py). For this, I have copied another model class and edited its name and fields and it is all fine. Lets call this new model class 'boom'.
My question is now how do I "create" this boom table using the migration script and the boom model?
I am worried that I might accidentally disrupt anything that is already in DB. How do I run the migration to create only boom table? How do I create a migration script specifically for it?
I know that it has something to do with manage.py and running migrate or runmigration (or is it sqlmigrate?...im confused). While creating the boom table, I dont want the database to go boom if you know what I mean :)
First, create a backup of your database. Copy it to your development machine. Try things out on that. That way it doesn't matter if it does go "boom" for some reason.
The first thing to do is
python manage.py showmigrations
This shows all the existing migrations, and it should show that they have been applied with an [X].
Then,
python manage.py makemigrations
Makes a new migration file for your new model (name 00004_...).
Then do
python manage.py migrate
to apply it. To undo it, go back to the state of migrations 00003, with
python manage.py migrate <yourappname> 00003
There are two steps to migrations in Django.
./manage.py makemigrations
will create the migration files that you see - these describe the changes that should be made to the database.
You also need to run
./manage.py migrate
this will apply the migrations and actually run the alter table commands in SQL to change the actual database structure.
Generally adding fields or tables won't affect anything else in the database. Be more careful when altering or deleting existing fields as that can affect your data.
The reason for two steps is so that you can make changes on a dev machine and once happy commit the migration files and release to your production environment. Then you run the migrate command on your production machine to bring the production database to the same state as your dev machine (no need for makemigrations on production assuming that your databases started the same).
My question is now how do I "create" this boom table using the
migration script and the boom model?
./manage.py makemigrations
I am worried that I might accidentally disrupt anything that is
already in DB.
The whole point of migrations, is that it doesn't
I know that it has something to do with manage.py and running migrate
or runmigration
For more information please refer to : https://docs.djangoproject.com/en/1.10/topics/migrations/
And rest assured that your database will not go boom! :-)
I solved it simply, changing the name of the new model to the original name, and then I checked if there is the table in the database, if not, I just create a new table with the old name with just a field like id.
And then clear migrations and create new migrations, migrate and verify table was fixed in DB and has all missing fields.
If it still doesn't work, then change the model name back to a new one.
but when django asks you if you are renaming the model you should say NO to get the old one removed properly and create a new one.
This type of error usually occurs when you delete some table in dB manually, and then the migration history changes in the tables are lost.
But it is not necessary to erase the entire database and start from scratch.

Why is Django creating my TextField as a varchar in the PostgreSQL database?

Django 1.7, Python 3.4.
In my models I have several TextFields defined.
When I go to load a JSON fixture (which was generated from an SQLite3 dump), it fails on the second object, which has 515 characters for one of its fields.
The error printed is
psycopg2.DataError: value too long for type character varying(500)
I created a new database (not just a table drop, a whole new db), modified my settings.py file, ran manage.py syncdb on the new database, created a user, and tried to load the data again, getting the same error.
Upon opening pgAdmin3, all columns, both CharField and TextField defined are listed as type character var.
So it seems TextField is being ignored and CharFields are being created instead. The PostgreSQL documentation explicitly lists both text and character types, and defines text as being unlimited in length. Any idea why?
I'm not sure what the exact cause was, but it seems to be related to django's migration tool storing migrations, even on a new database.
What I did to get this behavior:
Create django project, then apps, using CharField
syncdb, run the project's dev server
kill the devserver, modify fields to be TextField
Create a new Postgres database, modify settings.py
Run syncdb, attempt to load fixtures
See the error in question, examine db instance
What fixed the problem:
Create a new database, modify settings.py
delete all migrations in apps/migrations folders
after running syncdb, also run createmigrations and migrate
The last step generated a migration, even though there were none stored in the migrations folder, and there had been no changes to models or data since syncdb was run on the new database, which I found to be odd.
Somewhere in the last two steps this was fixed. Future people stumbling upon this: sorry, I'm not going to keep creating django projects to test the behavior further, but perhaps with this information you can fix your own database problems.

Migrate models with from one django app to several other apps

I have a django app which consists of 17 models. Now I have realized that these models should be in 3 different apps(not in the original app). So now I would like to migrate these models out of the original app to these 3 different apps. How do I do that?
There exists foreign key, generic foreign key and ManyToMany relationships among the models. I also have data in the database(MySql), so I would like the data to be preserved during migration.
I have installed south for migrations, but don't know how to use it for solving this issue. I have gone through this similar question but could not find an answer that would solve my problem. Would be thankful for any help !
In my opinion, you have two ways of completing this task as stated below:
Move the models and add Meta.db_table to refer the existing sql table as needed as #kroolik suggested
Perform a three steps migration
The former is easier while the later could be better as tables would be named as you expect.
First of all, you mention you already has south installed. The first step would be to create the initial migration for the existing app. Take a look to the south tutorial. Then you must apply that migration, but as you already has the tables in db it would fail unless you include --fake flag.
After that you need to create the three apps you mention, and their models. Also create and apply (this time without fake flag) the initial migration for them.
Next step is write a datamigration. You must write it manually, although you can create the skeleton with datamigration. You must write "by hand" the migration.
Now you are almost done, the only remaining thing is remove the original tables. You can just remove those models, and create an "auto" schemamigration.
Don't forget to apply the migrations with migrate command. Also as #Bibhas mention a copy of database and/or a dump of it is a pretty good idea.

Django: Change models without clearing all data?

I have some models I'm working with in a new Django installation. Is it possible to change the fields without losing app data?
I tried changing the field and running python manage.py syncdb. There was no output from this command.
Renavigating to admin pages for editing the changed models caused TemplateSyntaxErrors as Django sought to display fields that didn't exist in the db.
I am using SQLite.
I am able to delete the db file, then re-run python manage.py syncdb, but that is kind of a pain. Is there a better way to do it?
Django does not ever alter an existing database column. Syncdb will create tables, but it does not do 'migrations' as found in Rails, for instance. If you need something like that, check out Django South.
See the docs for syndb:
Syncdb will not alter existing tables
syncdb will only create tables for models which have not yet been installed. It will never issue ALTER TABLE statements to match changes made to a model class after installation. Changes to model classes and database schemas often involve some form of ambiguity and, in those cases, Django would have to guess at the correct changes to make. There is a risk that critical data would be lost in the process.
If you have made changes to a model and wish to alter the database tables to match, use the sql command to display the new SQL structure and compare that to your existing table schema to work out the changes.
You have to change the column names in your DB manually through whatever administration tools sqlite provides. I've done this with MySQL, for instance, and since MySQL lets you change column names without affecting your data, it's no problem.
Of course there is.
Check out South
You'll have to manually update the database schema/layout, if you're only talking about adding/removing columns.
If you're attempting to rename a column, you'll have to find another way.
You can use the python manage.py sql [app name] (http://docs.djangoproject.com/en/dev/ref/django-admin/#sql-appname-appname) command to see what the new SQL should look like, to see what columns, of what type/specification Django would have you add, and then manually run corresponding ALTER TABLE commands.
There are some apps/projects that enable easier model/DB management, but Django doesn't support this out of the box, on purpose/by design.

Categories