• No results found

Adding security-related data to the models

We will associate a game with a creator or owner. Only the authenticated users will be able to create new games. Only the creator of a game will be able to update it or delete it. All the requests that aren't authenticated will only have read-only access to games.

Open the games/models.py file and replace the code that declares the Game class with the following code. The line that changes is highlighted in the code listing. The code file for the sample is included in the restful_python_chapter_03_04 folder.

class Game(models.Model):

owner = models.ForeignKey(

'auth.User',

related_name='games', on_delete=models.CASCADE)

created = models.DateTimeField(auto_now_add=True) name = models.CharField(max_length=200, unique=True) game_category = models.ForeignKey(

GameCategory,

related_name='games', on_delete=models.CASCADE)

release_date = models.DateTimeField()

played = models.BooleanField(default=False) class Meta:

ordering = ('name',) def __str__(self):

return self.name

The Game model declares a new owner field that uses the django.db.models.ForeignKey class to provide a many-to-one relationship to the auth.User model, specifically, to the

django.contrib.auth.User model. This User model represents the users within the Django authentication system. The 'games' value specified for the related_name argument creates a backwards relation from the User model to the Game model. This value indicates the name to be used for the relation from the related User object back to a Game object. This way, we will be able to access all the games owned by a specific user. Whenever we delete a user, we want all the games owned by this user to be deleted too, and therefore, we specified the

models.CASCADE value for the on_delete argument.

Now, we will run the createsuperuser subcommand for manage.py to create the superuser

for Django that we will use to easily authenticate our requests. We will create more users later:

python manage.py createsuperuser

The command will ask you for the username you want to use for the superuser. Enter the desired user name and press Enter. We will use superuser as the user name for this example.

You will see a line similar to the following one:

Username (leave blank to use 'gaston'):

Then, the command will ask you for the e-mail address. Enter an e-mail address and press Enter:

Email address:

Finally, the command will ask you for the password for the new superuser. Enter your desired password and press Enter.

Password:

The command will ask you to enter the password again. Enter it and press Enter. If both entered passwords match, the superuser will be created:

Password (again):

Superuser created successfully.

Now, go to the gamesapi/games folder and open the serializers.py file. Add the following code after the last line that declares the imports, before the declaration of the

GameCategorySerializer class. The code file for the sample is included in the

restful_python_chapter_03_04 folder:

games = UserGameSerializer(many=True, read_only=True) class Meta:

The UserGameSerializer class is a subclass of the HyperlinkedModelSerializer class. We use this new serializer class to serialize the games related to a user. This class declares a Meta

inner class that declares two attributes: model and fields. The model attribute specifies the model related to the serializer, that is, the Game class. The fields attribute specifies a tuple of string whose values indicate the field names that we want to include in the serialization from the related model. We just want to include the URL and the game's name, and therefore, the code specified 'url' and 'name' as members of the tuple. We don't want to use the

GameSerializer serializer class for the games related to a user because we want to serialize fewer fields, and therefore, we created the UserGameSerializer class.

The UserSerializer class is a subclass of the HyperlinkedModelSerializer class. This class declares a Meta inner class that declares two attributes-model and fields. The model attribute specifies the model related to the serializer, that is, the django.contrib.auth.models.User

class.

The UserSerializer class declares a games attribute as an instance of the previously explained

UserGameSerializer with many and read_only equal to True because it is a one-to-many relationship and it is read-only. We use the games name that we specified as the related_name

string value when we added the owner field as a models.ForeignKey instance in the Game

model. This way, the games field will provide us with an array of URLs and names for each game that belongs to the user.

We will make more changes to the serializers.py file in the gamesapi/games folder. We will add an owner field to the existing GameSerializer class. The following lines show the new code for the GameSerializer class. The new lines are highlighted. The code file for the sample is included in the restful_python_chapter_03_04 folder:

class GameSerializer(serializers.HyperlinkedModelSerializer):

# We just want to display the owner username (read-only) owner = serializers.ReadOnlyField(source='owner.username') # We want to display the game cagory's name instead of the id

Now, the GameSerializer class declares an owner attribute as an instance of

serializers.ReadOnlyField with source equal to 'owner.username'. This way, we will

serialize the value for the username field of the related django.contrib.auth.User hold in the

owner field. We use the ReadOnlyField because the owner is automatically populated when an authenticated user creates a game, and therefore, it won't be possible to change the owner after a game has been created. This way, the owner field will provide us with the user name that created the game. In addition, we added 'owner' to the field's string tuple.

Creating a customized permission class for