Running migrations that generate relationships

We must create the initial migration for the new models we recently coded. We just need to run the following Python scripts and we will also synchronize the database for the first time. As we learned from our previous RESTful Web Service sample, by default, Django uses an SQLite database.

In this new example, we will be working with a PostgreSQL database. However, in case you want to use an SQLite, you can skip all the next steps related to PostgreSQL, its configuration in Django, and jump to the migrations generation command. You will also have to use the SQLite utilities instead of the PostgreSQL tools to analyze the database.

We will use the PostgreSQL command-line tools to create a new database named toys. In case you already have a PostgreSQL database with this name, make sure that you use another name in all the commands and configurations. You can perform the same tasks with any PostgreSQL GUI tool or any database administration tool that supports PostgreSQL.

In case you are developing in Linux, it is necessary to run the commands as the postgres user. Run the following command in Windows or macOS to create a new database named drones. Notice that the command won't produce any output and that you must have the bin folder for PostgreSQL command-line tools in your path:

createdb drones

In Linux, run the following command to use the postgres user:

sudo -u postgres createdb drones  

Now, we will use the psql command-line tool to run some SQL statements to create a specific user that we will use in Django and assign the necessary roles for it. In Windows or macOS, run the following command to launch the psql tool:

psql  

In macOS, you might need to run the following command to launch psql with the postgres user in case the previous command doesn't work, as it will depend on the way in which you installed and configured PostgreSQL:

sudo -u postgres psql  

In Linux, run the following command to start psql with the postgres user:

sudo -u psql 

Then, run the following SQL statements and finally enter q to exit the psql command-line tool.

Replace the username with your desired username to use in the new database, and password with your chosen password. We will specify the selected username and password in the Django settings for our web service.

You don't need to run the steps in case you are already working with a specific user in PostgreSQL and you have already granted privileges to the database for the user:

CREATE ROLE username WITH LOGIN PASSWORD 'password';
GRANT ALL PRIVILEGES ON DATABASE drones TO username;
ALTER USER username CREATEDB;
q  

You will see the following output for the previous commands:

CREATE ROLE
GRANT
ALTER ROLE  

The default SQLite database engine and the database file name are specified in the restful01/settings.py Python file. The following lines show the default lines that configure the database:

DATABASES = { 
    'default': { 
        'ENGINE': 'django.db.backends.sqlite3', 
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 
    } 
} 

We will work with PostgreSQL instead of SQLite for this example, and therefore, we must replace the declaration of the DATABASES dictionary with the following lines. The nested dictionary maps the database named default with the django.db.backends.postgresql database engine, the desired database name and its settings. In this case, we will create a database named drones. Make sure you specify the desired database name in the value for the 'NAME' key and that you configure the user, password, host, and port based on your PostgreSQL configuration. In case you followed the previously explained steps to configure the PostgreSQL database, use the settings specified in these steps. The code file for the sample is included in the hillar_django_restful_06_01 folder, in the restful01/settings.py file:

DATABASES = { 
    'default': { 
        'ENGINE': 'django.db.backends.postgresql', 
        # Replace drones with your desired database name 
        'NAME': 'drones', 
        # Replace username with your desired user name 
        'USER': 'username', 
        # Replace password with your desired password 
        'PASSWORD': 'password', 
        # Replace 127.0.0.1 with the PostgreSQL host 
        'HOST': '127.0.0.1', 
        # Replace 5432 with the PostgreSQL configured port 
        # in case you aren't using the default port 
        'PORT': '5432', 
    } 
}
In case you decided to continue working with SQLite, you don't need to make the previous changes and you can continue using the default configuration.

We don't want the migrations process to take into account our models related to toys from the previous web service, and therefore, we will make changes to the code in the urls.py file in the restful01 folder, specifically, the restful01/urls.py file. The file defines the root URL configurations, and therefore, we must remove the URL patterns declared in the toys/urls.py file. The following lines show the new code for the restful01/urls.py file. The code file for the sample is included in the hillar_django_restful_06_01 folder, in the restful01/urls.py file:

from django.conf.urls import url, include 
 
urlpatterns = [ 
] 

In order to use PostgreSQL, it is necessary to install a Python-PostgreSQL Database Adapter that Django will use to interact with a PostgreSQL database: the Psycopg2 package (psycopg2).

In macOS, we have to make sure that the PostgreSQL bin folder is included in the PATH environmental variable. For example, in case the path to the bin folder is /Applications/Postgres.app/Contents/Versions/latest/bin, we must execute the following command to add this folder to the PATH environmental variable:

export PATH=$PATH:/Applications/Postgres.app/Contents/Versions/latest/bin  

Once we make sure that the PostgreSQL bin folder is included in the PATH environmental variable, we just need to run the following command to install this package. Make sure the virtual environment is activated before running the command:

pip install psycopg2  

The last lines for the output will indicate that the psycopg2 package has been successfully installed:

Collecting psycopg2
Installing collected packages: psycopg2
Successfully installed psycopg2-2.7.3.2  

Now, run the following Python script to generate the migrations that will allow us to synchronize the PostgreSQL database for the first time. We will run the migrations for the drones application:

python manage.py makemigrations drones  

The following lines show the output generated after running the previous command:

Migrations for 'drones':
drones/migrations/0001_initial.py
- Create model Competition
- Create model Drone
- Create model DroneCategory
- Create model Pilot
- Add field drone_category to drone
- Add field drone to competition
- Add field pilot to competition

The output indicates that the restful01/drones/migrations/0001_initial.py file includes the code to create the Competition, Drone, DroneCategory, and Pilot models. 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 hillar_django_restful_06_01 folder, in the restful01/drones/migrations/0001_initial.py file:

# -*- coding: utf-8 -*- 
# Generated by Django 1.11.5 on 2017-11-02 02:55 
from __future__ import unicode_literals 
 
from django.db import migrations, models 
import django.db.models.deletion 
 
 
class Migration(migrations.Migration): 
 
    initial = True 
 
    dependencies = [ 
    ] 
 
    operations = [ 
        migrations.CreateModel( 
            name='Competition', 
            fields=[ 
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 
                ('distance_in_feet', models.IntegerField()), 
                ('distance_achievement_date', models.DateTimeField()), 
            ], 
            options={ 
                'ordering': ('-distance_in_feet',), 
            }, 
        ), 
        migrations.CreateModel( 
            name='Drone', 
            fields=[ 
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 
                ('name', models.CharField(max_length=250)), 
                ('manufacturing_date', models.DateTimeField()), 
                ('has_it_competed', models.BooleanField(default=False)), 
                ('inserted_timestamp', models.DateTimeField(auto_now_add=True)), 
            ], 
            options={ 
                'ordering': ('name',), 
            }, 
        ), 
        migrations.CreateModel( 
            name='DroneCategory', 
            fields=[ 
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 
                ('name', models.CharField(max_length=250)), 
            ], 
            options={ 
                'ordering': ('name',), 
            }, 
        ), 
        migrations.CreateModel( 
            name='Pilot', 
            fields=[ 
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 
                ('name', models.CharField(default='', max_length=50)), 
                ('gender', models.CharField(choices=[('M', 'Male'), ('F', 'Female')], default='M', max_length=2)), 
                ('races_count', models.IntegerField()), 
                ('inserted_timestamp', models.DateTimeField(auto_now_add=True)), 
            ], 
            options={ 
                'ordering': ('name',), 
            }, 
        ), 
        migrations.AddField( 
            model_name='drone', 
            name='drone_category', 
            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='drones', to='drones.DroneCategory'), 
        ), 
        migrations.AddField( 
            model_name='competition', 
            name='drone', 
            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='drones.Drone'), 
        ), 
        migrations.AddField( 
            model_name='competition', 
            name='pilot', 
            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='competitions', to='drones.Pilot'), 
        ), 
    ] 

The code defines a subclass of the django.db.migrations.Migration class named Migration that defines an operations list with many calls to migrations.CreateModel. Each migrations.CreateModel call will create the table for each of the related models.

Notice that Django has automatically added an id field for each of the models. The operations are executed in the same order in which they are displayed in the list. The code creates Competition, Drone, DroneCategory, Pilot and finally adds the following fields with foreign keys:

  • The drone_category field to the Drone model with the foreign key to the DroneCategory model
  • The drone field to the Competition model with the foreign key to the Drone model
  • The pilot field to the Competition model with the foreign key to the Pilot model

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 previous command:

Operations to perform:
Apply all migrations: admin, auth, contenttypes, drones, sessions
    Running migrations:
      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 auth.0008_alter_user_username_max_length... OK
      Applying drones.0001_initial... OK
      Applying sessions.0001_initial... OK
  
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.166.31