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.