Django tips

How to create an entity-relationship diagram

pip install pydotplus
python manage.py graph_models [app-name] -o graph.png

How to separate out changes to data and the schema

e.g. if you want to change something from NOT NULL to NULL.

  1. Create a blank migration for the data migration

  2. Add the code to change NULL to “” (or whatever) (something like this)

  3. Run migration locally

  4. Run makemigrations to get a migration with the schema changes

  5. Commit

The official docs about this are here: https://docs.djangoproject.com/en/2.2/topics/migrations/#data-migrations

Moving models between apps

Note

Taken, and corrected/added to, from fleschenberg.net. You may also find this advice on StackOverflow useful.

Moving a Django model to another app can be tricky. Here is a quick rundown of the most convenient way I found so far. The idea is to simply rename the database tables, and force Django to consider this the new state of your models. Thanks to Marten Kenbeek who pointed me at SeparateDatabaseAndState.

This is probably still missing some edge cases and I only tested it on one project, so be careful.

  1. Create a backup.

  2. Copy the model code to the new app. Update any foreign key references as necessary.

  3. Run manage.py makemigrations new_app

  4. Edit the migration:

operations=[
    migrations.SeparateDatabaseAndState(
        database_operations=None,
        state_operations=[
            # Copy the auto-generated operations here.
        ],
    )
]
  1. Delete the model(s)s from the old app.

  2. Run python manage.py makemigrations old_app

  3. Edit the migration:

operations = [
    migrations.SeparateDatabaseAndState(
        database_operations=[
            migrations.AlterModelTable('MyModel', 'newapp_mymodel'),
            # Repeat for the other models you want to move.
            # The model name should be in caps in the first one, and lowercase in
            # the second.
        ],
        state_operations=[
            # Copy the auto-generated operations here.
        ],
    )
]
  1. python manage.py migrate

It’s best to deploy one change like this at a time, if possible.

You might find you have to alter other migrations in other apps. For example, in the CRM, membership turned into crm. But older migration files were still using “membership”:

models.OneToOneField(
    on_delete=django.db.models.deletion.CASCADE,
    primary_key=True,
    related_name="membership",
    serialize=False,
    to="membership.Contact",
)

This resulted in endless errors like:

… code-block:: python

ValueError: Related model ‘membership.Membership’ cannot be resolved

So just search for instances of to="old_app_name.Model" and change it to reference the new app name.

Removing fields

If you’re removing a field from a model and you want to catch everywhere that it was used, you should use something like the following to replace it:

def _fail_name(self):
    raise ValueError("Property 'name' removed; use display_name instead")

name = property(_fail_name, _fail_name, _fail_name)

This will throw an exception on any access to the named attribute.