Creating the models
Now, we will create a simple Game
model that we will use to represent and persist games. Open the games/models.py
file. The following lines show the initial code for this file, with just one import statement and a comment that indicates we should create the models:
from django.db import models # Create your models here.
The following lines show the new code that creates a Game
class, specifically, a Game
model in the games/models.py
file. The code file for the sample is included in the restful_python_chapter_01_01
folder:
from django.db import models class Game(models.Model): created = models.DateTimeField(auto_now_add=True) name = models.CharField(max_length=200, blank=True, default='') release_date = models.DateTimeField() game_category = models.CharField(max_length=200, blank=True, default='') played = models.BooleanField(default=False) class Meta: ordering = ('name',)
The Game
class is a subclass of the django.db.models.Model
class. Each defined attribute represents a database column or field. Django automatically adds an auto-increment integer primary key column named id
when it creates the database table related to the model. However, the model maps the underlying id
column in an attribute named pk
for the model. We specified the field types, maximum lengths and defaults for many attributes. The class declares a Meta inner class that declares a ordering attribute and sets its value to a tuple of string whose first value is the 'name'
string, indicating that, by default, we want the results ordered by the name
attribute in ascending order.
Then, it is necessary to create the initial migration for the new Game
model we recently coded. We just need to run the following Python scripts and we will also synchronize the database for the first time. By default, Django uses an SQLite database. In this example, we will be working with this default configuration:
python manage.py makemigrations games
The following lines show the output generated after running the preceding command.
Migrations for 'games': 0001_initial.py: - Create model Game
The output indicates that the gamesapi/games/migrations/0001_initial.py
file includes the code to create the Game
model. The following lines show the code for this file that was automatically generated by Django. The code file for the sample is included in the restful_python_chapter_01_01
folder:
# -*- coding: utf-8 -*- # Generated by Django 1.9.6 on 2016-05-17 21:19 from __future__ import unicode_literals from django.db import migrations, models class Migration(migrations.Migration): initial = True dependencies = [ ] operations = [ migrations.CreateModel( name='Game', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('created', models.DateTimeField(auto_now_add=True)), ('name', models.CharField(blank=True, default='', max_length=200)), ('release_date', models.DateTimeField()), ('game_category', models.CharField(blank=True, default='', max_length=200)), ('played', models.BooleanField(default=False)), ], options={ 'ordering': ('name',), }, ), ]
The code defines a subclass of the django.db.migrations.Migration
class named Migration
that defines an operation that creates the Game
model's table. Now, run the following python script to apply all the generated migrations:
python manage.py migrate
The following lines show the output generated after running the preceding command:
Operations to perform: Apply all migrations: sessions, games, contenttypes, admin, auth Running migrations: Rendering model states... DONE Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying games.0001_initial... OK Applying sessions.0001_initial... OK
After we run the preceding command, we will notice that the root folder for our gamesapi
project now has a db.sqlite3
file. We can use the SQLite command line or any other application that allows us to easily check the contents of the SQLite database to check the tables that Django generated.
In macOS and most modern Linux distributions, SQLite is already installed, and therefore, you can run the sqlite3
command-line utility. However, in Windows, if you want to work with the sqlite3.exe
command-line utility, you will have to download and install SQLite from its Web page-http://www.sqlite.org.
Run the following command to list the generated tables:
sqlite3 db.sqlite3 '.tables'
Run the following command to retrieve the SQL used to create the games_game
table:
sqlite3 db.sqlite3 '.schema games_game'
The following command will allow you to check the contents of the games_game
table after we compose and send HTTP requests to the RESTful API and make CRUD operations to the games_game
table:
sqlite3 db.sqlite3 'SELECT * FROM games_game ORDER BY name;'
Instead of working with the SQLite command-line utility, you can use a GUI tool to check the contents of the SQLite database. DB Browser for SQLite is a useful multiplatform and free GUI tool that allows us to easily check the database contents of an SQLite database in macOS, Linux and Windows. You can read more information about this tool and download its different versions from http://sqlitebrowser.org. Once you installed the tool, you just need to open the db.sqlite3
file and you can check the database structure and browse the data for the different tables. You can use also the database tools included in your favorite IDE to check the contents for the SQLite database.
The SQLite database engine and the database file name are specified in the gamesapi/settings.py
Python file. The following lines show the declaration of the DATABASES
dictionary that contains the settings for all the database that Django uses. The nested dictionary maps the database named default
with the django.db.backends.sqlite3
database engine and the db.sqlite3
database file located in the BASE_DIR
folder (gamesapi
):
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } }
After we executed the migrations, the SQLite database will have the following tables:
auth_group
auth_group_permissions
auth_permission
auth_user
auth_user_groups
auth_user_groups_permissions
django_admin_log
django_content_type
django_migrations
django_session
games_game
sqlite_sequence
The games_game
table persists in the database the Game
class we recently created, specifically, the Game
model. Django's integrated ORM generated the games_game
table based on our Game
model. The games_game
table has the following rows (also known as fields) with their SQLite types and all of them are not nullable:
id
: The integer primary key, anautoincrement
rowcreated
:datetime
name
:varchar(200)
release_date
:datetime
game_category
:varchar(200)
played
:bool
The following lines show the SQL creation script that Django generated when we executed the migrations:
CREATE TABLE "games_game" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "created" datetime NOT NULL, "name" varchar(200) NOT NULL, "release_date" datetime NOT NULL, "game_category" varchar(200) NOT NULL, "played" bool NOT NULL )
Django generated additional tables that it requires to support the Web framework and the authentication features that we will use later.