Get Django Updates

The typical way for Django applications to interact with data is through Django models. A Django model is an object orientated Python class that represents the characteristics of an entity. For example, an entity can be a person, a company, a product or some other concept used by an application.

Because data is at the center of modern applications and the Django framework enforces the DRY (Don't Repeat Yourself) principle, Django models often serve as the building blocks for Django projects. Once you have a set of Django models representing an application's entities, Django models can also serve as the basis to simplify the creation of other Django constructs that operate with data (e.g. forms, class-based views, REST services, Django admin pages), hence the importance of Django models as a whole.

In this chapter you'll learn about the core behaviors of Django models, including how to create models and how to use migrations which are central to working effectively with models. Next, you'll learn about the default behaviors of Django models and how to override them with custom behaviors. In addition, you'll learn about the different data types available to create Django models, the different relationships available for Django models and how to manage database transactions with Django models.

Next, you'll learn more about migration files, including the various ways to create migration files, how to rename migration files, how to squash multiple migration files into a single migration file, the meaning behind each migration file element so you can edit migration files with confidence and the procedure to rollback migration files.

In addition, you'll learn about the various Django tools designed to ease the work between Django models and databases, such backing-up and loading model data with fixture files, including how to load initial data into Django models. Next, you'll learn about Django signals which support the software observer pattern in Django models. Finally, you'll finish the chapter learning how to declare Django models outside of their default location, as well as how to configure multiple databases and use them with Django models.

This chapter assumes you've already set up a database for a Django project. If you haven't set up a database, see Chapter 1 on setting up a database for a Django project.

Django models and the migrations workflow

Django's primary storage technology is relational (i.e. out-of-the-box it can connect to SQLite, Postgres, MySQL or Oracle), so a Django model is designed to map directly to a relational database table. This means instances of a Django model are stored as rows of a relational table named after the model.

For example, for a Django model class named Store, by default Django performs database CRUD (Create, Read, Update and Delete) operations on a database table called <app_name>_store, where each of the model's Store instances represent database rows and a model's fields (e.g. name, address, city, state) map to database table columns.

Because Django models revolve around data, they are prone to change. For example, a Django model named Store can suddenly require the modification of its original fields due to business requirements (e.g. the addition of a new field like email or the removal of a field that's no longer needed like telephone). Maintaining these Django models changes throughout time is also an important aspect of Django models and is managed through the use migration files.

Create Django models

Django models are stored in models.py files located inside Django apps. As soon as you create a Django app, an empty models.py file is added to the app for future use. If you're unfamiliar with the term Django app, see the Chapter 1 section on setting up content. Listing 7-1 illustrates a sample Django model definition.

Tip Remember the book's code is at https://github.com/drubio/beginningdjango , if you find it easier to follow along with a pre-typed and structured application.

Listing 7-1 Django model class definition in models.py

from __future__ import unicode_literals
from django.utils.encoding import python_2_unicode_compatible
from django.db import models
@python_2_unicode_compatible
class Store(models.Model):
    #id = models.AutoField(primary_key=True)# Added by default, not required explicitly 
    name = models.CharField(max_length=30)    
    address = models.CharField(max_length=30)
    city = models.CharField(max_length=30)
    state = models.CharField(max_length=2)
    #objects = models.Manager()# Added by default, to required explicitly 
    def __str__(self):
        return "%s (%s,%s)" % (self.name, self.city, self.state)

The first two lines in listing 7-1 import the functionality required to run Python classes in Django using both Python 2 and Python 3. If your Django project will just run on Python 3, you can omit these import statements. The third line in listing 7-1 imports the django.db.models package which is necessary to access Django model functionality in the class definition. Next, you can see the class Store(models.Model) statement. The @python_2_unicode_compatible annotation is required to run the class on Python 2, but if you just use Python 3 you can omit this annotation.

After the main class definition in listing 7-1, you can see four fields with the models.CharField data type which qualifies the fields as character strings. Further restricting the acceptable values for each field is the max_length argument for models.CharField (e.g. max_length=30 indicates the maximum length for the character field is 30 characters).

For the moment, don't worry about the models.CharField field definitions. There are many other data types and arguments supported by Django's models package, I'll describe all of these options in the next section on Django model data types.

In addition, notice the Django model in listing 7-1 has the id and objects fields. In this case, I commented them out with # because you don't need to explicitly declare them, both are automatically added to all Django models, but I put them there so you know they exists.

The id field is a Django AutoField data type, that behind the scenes creates an integer table column that increments automatically. For example, when you create the first Store record, the id field is set to 1 by the database, for the second Store record the database sets the id field to 2, and so on. The intent of the id field is to make record searches easier and more efficient. Because the id represents a unique number to identify a record, it's used as a reference, which is also used as a database table's primary key and as an index to speed up record access. While you can override various behaviors of this default id field (e.g. change the field name), I'll leave the details of this for a later section.

The objects field is a Django model's default model manager, charged with managing all the query operations associated with a Django model. Future sections in this chapter and the following chapter describe the use of Django model managers.

Tip If you want to know more about the id field added by default to all Django models: Table 7-2 describes the AutoField data type which is the basis for the id field; the section 'Django model data types' later in this chapter describes the purpose of the primary_key attribute used by the id field; and the save() method described in the 'Model methods' section later in this chapter describes the practical aspects of the id field.

Finally, in listing 7-1 you can see the class method definition for __str__ which is a standard Python method -- part of what are called 'magic methods' -- that are helpful when attempting to view or print instances of Django models. The __str__ method defines a human readable representation of a class instance (e.g. a Store model instance based on listing 7-1 is output by its name, city and state field values).

Django model definitions even when placed in an app's models.py file still aren't discoverable by Django. In order for Django to discover model definitions in models.py files, it's necessary to declare apps as part of the INSTALLED_APPS variable in settings.py. Listing 7-2 illustrates an INSTALLED_APPS definition to discover Django models in the coffeehouse.stores app.

Listing 7-2. Add app to INSTALLED_APPS in Django settings.py to detect models.py definitions

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'coffeehouse.stores',
)

As you can see in listing 7-2, in addition to the default apps declared in INSTALLED_APPS the coffeehouse.stores app is added at the end. This tells Django to inspect the models.py file in the coffeehouse.stores app to take into account any Django model definitions in it.

After the previous steps, an app's Django model definitions in models.py are ready for use. In the next section, I'll describe Django model migrations and the workflow associated with models in models.py files.

Migrations and the Django model workflow

Let's start with an illustration of how the Django models workflow operates with migrations thrown into the mix. Figure 7-1 shows the Django models workflow with migrations.

Figure 7-1 Django workflow for models with migrations

Illustrated on the top-left side of figure 7-1, the workflow starts when you add or modify Django models on a models.py file. Once you deem the changes made to a models.py file are considerable or want them reflected on a database, you need to create a migration file. Migration files provide a step-by-step snapshot of the changes made to a models.py file, whether you add, remove or modify content from the models.py file.

In order to create migration files you use the makemigrations management command. When you run this command, Django scans the models.py files for all Django apps declared in INSTALLED_APPS, if Django detects a change to a models.py file, it creates a new migration file for the app. This process functions like a version control system, where migration files reflect changes made to models.py from a prior a migration file, and the entire series of migration files tells the whole evolution of an app's models.py file.

As you can see in figure 7-1, migration files are stored in a /migrations/ sub-directory inside an app, alongside the models.py file they track. And by default, migration files use the naming convention <number_shortdescription> so it's easy to track in what order they were created and what it's they contain.

Next, lets run makemigrations on the Django model you created in the last section. Listing 7-3 illustrates this sequence and adds the stores argument to limit the migration process to the stores app -- if you run makemigrations without any argument, Django inspects the models.py for every app in defined in the INSTALLED_APPS variable in settings.py.

Listing 7-3. Django makemigrations command to create migration file for changes made to models.py

[user@coffeehouse ~]$ python manage.py makemigrations stores
Migrations for 'stores':
  0001_initial.py:
    - Create model Store

After running makemigrations stores in listing 7-3, you can see the migration file 0001_initial.py. The file is given this name because it's the first migration parting from an empty models.py. Future changes to the models.py generate migration files named 0002.,0003...

Turning our attention back the the workflow in figure 7-1, migration files by themselves are just a first step in the Django models workflow. Next, you can either preview or apply these migration files so the models become part of a database.

To preview the actual SQL statements for a migration before they're applied to a database you run the sqlmigrate <app_name> <migration_name> command. Listing 7-4 illustrates the sqlmigrate sequence for the migration file from the last step.

Listing 7-4. Django sqlmigrate command to preview SQL generated by migration file

[user@coffeehouse ~]$ python manage.py sqlmigrate stores 0001
BEGIN;
CREATE TABLE "stores_store"
   ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
    "name" varchar(30) NOT NULL,
    "address" varchar(30) NOT NULL,
    "city" varchar(30) NOT NULL,
    "state" varchar(2) NOT NULL);
COMMIT;

As you can see in listing 7-4, the migration file 0001_initial.py for the stores app is set to run an SQL statement that creates a database table named stores_store with field names that correspond to the Django model from listing 7-1.

Tip You can change a Django model's default database table name with the db_table Meta class option, the 'Model meta class' section describes this in detail.

Previewing the SQL statements generated by a migration file might not seem too exciting at this stage, but it can be very helpful in other circumstances. For example, if you make complex changes to a Django model or your database is relatively large, it's beneficial to preview the SQL before applying the migration file directly to a database.

Finally, the last step in the workflow for Django models is to apply the migration files to a database with the migrate command. Listing 7-5 illustrates this sequence and adds the stores argument to limit the process to the stores app -- if you run migrate without any argument, Django processes the migration files for every app in a project.

Listing 7-5 Django migrate command to execute migration files on database

[user@coffeehouse ~]$ python manage.py migrate stores
Operations to perform:
  Apply all migrations: stores
Running migrations:
  Applying stores.0001_initial... OK

In listing 7-5 the stores.0001_initial migration is run against the database. This means the SQL presented in listing 7-4 is executed against the database.

Caution Be careful manipulating the database directly without applying the same changes via Django migrations, as this can lead to inconsistencies and errors.
Tip If you don't want a Django model to use migrations, you can use the managed Meta class option, see the 'Django meta class' section for details.

To keep track of applied migrations, on the bottom-left side of figure 7-1 you can see the use of the showmigrations management command. The showmigrations command outputs a list of project migrations, with an X besides those migration files that have been applied to a database. It's worth mentioning the showmigrations command obtains its data by inspecting migration files in migration folders and the django_migrations database table that keeps track of applied migrations.