Django -south - Checking for existing table within migration - django

Some of my migrations should be run only when certain conditions are met - mostly because of the buggy nature of using south to migrate a django.contrib. needed when converting to our own user model. But since those migrations should run automatically I can't count on "--fake" - Sometime I need to run them, and sometime not - depending if the relation auth_permissions, for example, exists.
can I use the south/django orm in a migration forward section to check for an existing relation and run the migration in aif clause?
I tried using try/except in the migration but it seems to cause an error (currently can't reproduce that, I don't have this code any more)
How can I achieve that?
Thanks for the help!
Using Django 1.6.4 and south 0.8.4

Related

Creating migrations for a Django project that does not have any migrations already

I am working for a client with a 13 year old Django project. When they built the project migrations were not implemented so the project currently lacks migrations. I have tried creating migrations and then doing a datadump and loaddata into a new database to test them out. I am running into all sorts of errors and would like to start fresh.
So my question is this. What steps should I take to implement migrations in the project so that we can move forward using migrations? The django version has been updated to 3.0.5 and there are a number of GenericForeignKeys used, which might make this extra tricky. When creating the migrations originally I was told to use the fake tag but don't completely understand what this means.
Any help in the steps that I should take would be appreciated. For the sake of privacy/security for the client I don't want to just share a ton of their code but can share parts of it if it helps someone determine the steps that I should take.
For reference. After creating migration files originally and then trying the dumdata/loaddata commands I typically get an error saying that there are duplicate entries relating to contenttypes or duplicate entries for django_site domains. The client has domains set up depending on where in the world they are logging in from so the site "name" is unique but the "domain" is the same.
(1062, "Duplicate entry 'www.example.com' for key 'django_site.django_site_domain_a2e37b91_uniq'")
If you are talking about working on local, simply, delete all the migrations (except migrations/__init__.py.) and makemigrations again.
If you are on production, you are safe to use --fake once.
You are OK also to change the old migrations if you know how to do deal with migrations, and if it is few files.
I have answered a similar question here.

Techniques to Avoid Problems with Django Migrations?

I'm building an e-commerce website with Django 1.8 and PostgreSQL 9.4. I'm interested in learning what techniques I can use when I change my database to avoid having problems with Django migrations, particularly in the event that I can't get migrations to run and I have to delete my migrations, rebuild my database, and restore from backups.
In development, I've found that when I change my database schema and re-run migrations, they only run successfully about 50% of the time. Clearly I'm doing some things wrong. What's worse is that when migrations don't work, it's not always easy to understand exactly why they failed and how to modify my migration files so that they will run. In those situations, I always have to delete the database and start over. This is acceptable in development but it's not a good strategy when I go into production.
What are some "best practices" or "do's and don'ts" you follow when you modify your model classes/database schema so as to increase the probability that your Django migrations will run? And are there any steps you take to ensure that you can restore your database in the event that your migrations won't run and you have to rebuild the database from scratch? I should add that I'm a one-person startup so I don't have the conflict issues that a team working from the same code base would have.
These Techniques are what I'm using
Work locally in the same environment what I'm working in it on server. Same version of the Django and database server then push the migrations itself, don't ignore it, and migrate on the server using there migrations.
This one I used once that I migrate manually, I created the tables, indices, relations using sql commands manually and it worked properly too.
I prefer the first one more

--fake-initial vs --fake in Django migration?

What is the difference between --fake-initial and --fake in Django migrations? What are the dangers of using fake migrations? Anybody knows? Thank you very much to all.
I am using django 1.10
Well the documentation is very clear about this
--fake-initial
Allows Django to skip an app’s initial migration if all database
tables with the names of all models created by all CreateModel
operations in that migration already exist. This option is intended
for use when first running migrations against a database that
preexisted the use of migrations. This option does not, however, check
for matching database schema beyond matching table names
You were asking about the risks, well here it is
only safe to use if you are confident that your existing schema
matches what is recorded in your initial migration.
--fake
Tells Django to mark the migrations as having been applied or
unapplied, but without actually running the SQL to change your
database schema.
This is intended for advanced users to manipulate the current
migration state directly if they’re manually applying changes;
Once again risks are clearly highlighted
be warned that using --fake runs the risk of putting the migration
state table into a state where manual recovery will be needed to make
migrations run correctly.
This answer is valid not just for django versions 1.8+ but for other versions as well.
edit Nov, 2018: I sometimes I see answers here and elsewhere that suggest that you should drop your databae. That's almost never the right thing to do. If you drop your database you lose all your data.
#e4c5 already gave an answer about this question, but I would like to add one more thing concerning when to use --fake and --fake-initial.
Suppose you have a database from production and you want to use it for development and apply migrations without destroying the data. In that case --fake-initial comes in handy.
The --fake-initial will force Django to look at your migration files and basically skip the creation of tables that are already in your database. Do note, though, that any migrations that don’t create tables (but rather modify existing tables) will be run.
Conversely, If you have an existing project with migration files and you want to reset the history of existing migrations, then --fake is usually used.
Short answer
--fake does not apply the migration
--fake-initial might, or might not apply the migration
Longer answer:
--fake: Django keeps a table called django_migrations to know which migrations it has applied in the past, to prevent you from accidentally applying them again. All --fake does is insert the migration filename into that table, without actually running the migration. This is useful if you manually changed the database schema first, and the models later, and want to bypass django's actions. However, during that step you are on your own, so take care that you don't end up in an inconsistent state.
--fake-initial: depends on the state of the database
all of the tables already exist in the database: in that case, it works like --fake. Only the names of the tables are checked, not their actual schema, so, again, take care
none of the tables already exist in the database: in that case, it works like a normal migration
some of the table already exist: you get an error. That's not supposed to happen, either you take care of the database, or django does.
Note that, --fake-initial is only taken into account if the migration file has initial=True in its class, otherwise the flag is ignored. Also, this is the only documented usage of initial=True in migrations.

Is there a way to update the database with the changes in my models? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
update django database to reflect changes in existing models
I've used Django in the past and one of the frustrations I've had with it as an ORM tools is the inability to update an existing database with changes in the model. (Hibernate does this very well and makes things really easy for updating and heavily modifying a model and applying this to an existing database.) Is there a way to do this without wiping the database every time? It gets really old having to regenerate admin users and sites after every change in the model which I'd like to play with.
You will want to look into South. It provides a migrations system to migrate both schema changes as well as data from one version to the next.
It's quite powerful and the vast majority of changes can be handled simple by going
manage.py schemamigration --auto
manage.py migrate
The auto functionality does have it limits, and especially if the change is going to be run on a production system eventually you should check the code --auto generated to be sure it's doing what you expect.
South has a great guide to getting started and is well documented. You can find it at http://south.aeracode.org
No.
As the documentation of syncdb command states:
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.
South seems to be how most people solve this problem, but a really quick and easy way to do this is to change the db directly through your database's interactive shell. Just launch your db shell (usually just dbshell) and manually alter, add, drop the fields and tables you need changed using your db syntax.
You may want to run manage.py sqlall appname to see the sql statements Django would run if it was creating the updated table, and then use those to alter the database tables and fields as required.
The Making Changes to a Database Schema section of the Django book has a few examples of how to do this: http://www.djangobook.com/en/1.0/chapter05/
I manually go into the database - whatever that may be for you: MySQL, PostgreSQL, etc. - to change database info, and then I adjust the models.py accordingly for reference. I know there is Django South, but I didn't want to bother with using another 3rd party application.

Is it possible to make Django's syndb command NOT try to create actual foreign keys in the database?

I'm no Django expert, but from what I can gather, there is no way to tell syndb not to try to run ALTER statements to create foreign key constraints on the db.
I recently tried to upgrade my MySQL Cluster installation from 7.0.6 to the latest release 7.1.9a. This revealed a bug in this latest MySQL release in which foreign key constructs are NOT ignored on engines that do not support them as they were in previous versions. This is definitely a MySQL bug which I have submitted to them and they have verified as valid.
In the mean time, however, until that bug is fixed, I'm stuck running a very old version of MySQL and wondered if I could possibly work around it by somehow forcing syncdb NOT to try to actually create foreign keys on the database, just create the tables.
Without getting into detail, in my case the syncdb command is built into some automation that does a lot more than just build a database from models, so I can't very easily work around this manually.
Any input or ideas are appreciated.
South can do this (http://south.aeracode.org/)
You could do a schemamigration and then edit the migration by hand, leaving out the FK constructs. You could also make your own introspection rules in South that automates this, I guess. It might interfere with your syncdb automation, though.
You can run python manage.py sqlall app_name, remove the ALTER FK constraints, and load the SQL manually.