Setting a default value for a new required field in migrations

We have persisted many games in our database and added a new owner field for the games that is a required field. We don't want to delete all the existing games, and therefore, we will take advantage of some features in Django that make it easy for us to make the changes in the underlying database without losing the existing data.

Now, we need to retrieve the id for the superuser we have created to use it as the default owner for the existing games. Django will allow us to easily update the existing games to set the owner user for them.

Run the following commands to retrieve the id from the auth_user table for the row that whose username is equal to 'superuser'. Replace superuser with the user name you selected for the previously created superuser. In addition, replace user_name in the command with the user name you used to create the PostgreSQL database and password with your chosen password for this database user. The command assumes that you are running PostgreSQL on the same computer in which you are running the command. In case you are working with a SQLite database, you can run the equivalent command in the PostgreSQL command line or a GUI-based tool to execute the same query.

psql --username=user_name --dbname=games --command="SELECT id FROM auth_user WHERE username = 'superuser';"

The following lines show the output with the value for id: 1

id 
----
  1
(1 row)

Now, run the following Python script to generate the migrations that will allow us to synchronize the database with the new field we added to the Game model:

python manage.py makemigrations games

Django will display the following question:

You are trying to add a non-nullable field 'owner' to game without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows)
 2) Quit, and let me add a default in models.py
Select an option: 

We want to provide the one-off default that will be set on all existing rows, and therefore, enter 1 to select the first option and press Enter .

Django will display the following text asking us to enter the default value:

Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now()
>>>

Enter the value for the previously retrieved id, 1 in our example, and press Enter. The following lines show the output generated after running the preceding command:

Migrations for 'games':
  0003_game_owner.py:
    - Add field owner to game

The output indicates that the gamesapi/games/migrations/0003_game_owner.py file includes the code to add the field named owner to game. 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_03_04 folder:

# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-07-01 21:06
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
    dependencies = [
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
        ('games', '0002_auto_20160623_2131'),
    ]
    operations = [
        migrations.AddField(
            model_name='game',
            name='owner',
            field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='games', to=settings.AUTH_USER_MODEL),
            preserve_default=False,
        ),
    ]

The code declares a subclass of the django.db.migrations.Migration class named Migration that defines an operations list with a migrations.AddField that will add the the owner field to the table related to the game model.

Now, run the following python script to apply all the generated migrations and execute the changes in the database tables:

python manage.py migrate

The following lines show the output generated after running the previous command. Note that the ordering for the migrations might be different in your configuration:

Operations to perform:
  Apply all migrations: admin, auth, contenttypes, games, sessions
Running migrations:
  Rendering model states... DONE
  Applying games.0003_game_owner... OK

After we run the previous command, we will have a new owner_id field added to the games_game table in the PostgreSQL database. The existing rows in the games_game table will use the default value we indicated Django to use for the new owner_id field. We can use the PostgreSQL command line or any other application that allows us to easily check the contents of the PostreSQL database to check the games_game table that Django updated. In case you decide to continue working with SQLite, use the commands or tools related to this database.

Run the following command to launch the interactive shell. Make sure you are within the gamesapi folder in the Terminal or Command Prompt:

python manage.py shell

You will notice that a line that says (InteractiveConsole) is displayed after the usual lines that introduce your default Python interactive shell. Enter the following code in the Python interactive to create another user that is not a superuser. We will use this user and the superuser to test our changes in the permissions policies. The code file for the sample is included in the restful_python_chapter_03_04 folder, in the users_test_01.py file.

You can replace kevin with your desired user name, [email protected] with the e-mail and kevinpassword with the password you want to use for this user. However, take into account that we will be using these credentials in the following sections. Make sure you always replace the credentials with your own credentials:

from django.contrib.auth.models import User 
user = User.objects.create_user('kevin', '[email protected]', 'kevinpassword')  
user.save() 

Finally, quit the interactive console by entering the following command:

quit() 

Now, we can launch Django's development server to compose and send HTTP requests. Execute any of the following two commands based on your needs to access the API in other devices or computers connected to your LAN. Remember that we analyzed the difference between them in Chapter 1, Developing RESTful APIs with Django:

python manage.py runserver
python manage.py runserver 0.0.0.0:8000

After we run any of the preceding commands, the development server will start listening at port 8000.

..................Content has been hidden....................

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