Managing serialization and deserialization with relationships and hyperlinks

Our new RESTful Web API has to be able to serialize and deserialize the EsrbRating, Game, Player, and PlayerScore instances into JSON representations. In this case, we also have to pay special attention to the relationships between the different models when we create the serializer classes to manage serialization to JSON and deserialization from JSON.

In our last version of the previous API, we created a subclass of the rest_framework.serializers.ModelSerializer class to make it easier to generate a serializer and reduce boilerplate code. In this case, we will also declare a class that inherits from ModelSerializer but three classes will inherit from the rest_framework.serializers.HyperlinkedModelSerializer class.

HyperlinkedModelSerializer is a type of ModelSerializer that uses hyperlinked relationships instead of primary key relationships, and therefore, it represents the relationships to other model instances with hyperlinks instead of primary key values. In addition, HyperlinkedModelSerializer generates a field named url with the URL for the resource as its value. As happens with ModelSerializer, the HyperlinkedModelSerializer class provides default implementations for the create and update methods.

Open the serializers.py file in the games_service/games folder. Replace the code in this file with the following lines. The new code declares the required imports and the EsrbRatingSerializer class. We will add more classes to this file later. The code file for the sample is included in the restful_python_2_06_01 folder, in the Django01/games-service/games/serializers.py file:

from rest_framework import serializers 
from games.models import EsrbRating 
from games.models import Game 
from games.models import Player 
from games.models import PlayerScore 
import games.views 
 
 
class EsrbRatingSerializer(serializers.HyperlinkedModelSerializer): 
    games = serializers.HyperlinkedRelatedField( 
        many=True, 
        read_only=True, 
        view_name='game-detail') 
 
    class Meta: 
        model = EsrbRating 
        fields = ( 
            'url', 
            'id', 
            'description', 
            'games') 

The EsrbRatingSerializer class is a subclass of the HyperlinkedModelSerializer superclass. The EsrbRatingSerializer class declares a games attribute as an instance of serializers.HyperlinkedRelatedField 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 created the esrb_rating field as a models.ForeignKey instance in the Game model. This way, the games field will provide us with an array of hyperlinks to each game that belongs to the ESRB rating. The view_name value is 'game-detail' because we want the browsable API feature to use the game detail view to render the hyperlink when the user clicks or taps on it.

The EsrbRatingSerializer class declares a Meta inner class that declares the following two attributes:

  • model: This attribute specifies the model related to the serializer, that is, the EsrbRating class.
  • fields: This attribute specifies a tuple of the string whose values indicate the field names that we want to include in the serialization from the related model. We want to include both the primary key and the URL, and therefore, the code specifies both 'id' and 'url' as members of the tuple.

There is no need to override either the create or update methods because the generic behavior will be enough in this case. The HyperlinkedModelSerializer superclass provides implementations for both methods.

Open the serializers.py file in the games_service/games folder and add the following lines after the last line to declare the GameSerializer class. The code file for the sample is included in the restful_python_2_06_01 folder, in the Django01/games-service/games/serializers.py file:

class GameSerializer(serializers.HyperlinkedModelSerializer): 
    # We want to display the game ESRB rating description instead of its id 
    esrb_rating = serializers.SlugRelatedField( 
        queryset=EsrbRating.objects.all(),  
        slug_field='description') 
 
    class Meta: 
        model = Game 
        fields = ( 
            'url', 
            'esrb_rating', 
            'name', 
            'release_date', 
            'played_once', 
            'played_times') 

The GameSerializer class is a subclass of the HyperlinkedModelSerializer superclass. The GameSerializer class declares an esrb_rating attribute as an instance of the serializers.SlugRelatedField class with its queryset argument set to EsrbRating.objects.all() and its slug_field argument set to 'description'.

SlugRelatedField is a read-write field that represents the target of the relationship by a unique slug attribute, that is, the description.

We created the esrb_rating field as a models.ForeignKey instance in the Game model and we want to display the ESRB rating's description value as the description (slug field) for the related EsrbRating. Hence, we specified 'description' as the slug_field. If it is necessary to display the possible options for the related ESRB rating in a form in the browsable API, Django will use the expression specified in the queryset argument to retrieve all the possible instances and display their specified slug field.

The EsrbRatingSerializer class declares a Meta inner class that declares the following two attributes:

  • model: This attribute specifies the model related to the serializer, that is, the Game class.
  • fields: This attribute specifies a tuple of the 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 therefore, the code specifies 'url' as a member of the tuple but doesn't specify 'id'. The esrb_rating field will specify the description field for the related EsrbRating.

Open the serializers.py file in the games_service/games folder and add the following lines after the last line to declare the ScoreSerializer class. The code file for the sample is included in the restful_python_2_06_01 folder, in the Django01/games-service/games/serializers.py file:

class ScoreSerializer(serializers.HyperlinkedModelSerializer): 
    # We want to display all the details for the related game 
    game = GameSerializer() 
    # We don't include the player because a score will be nested in the player 
 
    class Meta: 
        model = PlayerScore 
        fields = ( 
            'url', 
            'id', 
            'score', 
            'score_date', 
            'game') 

The ScoreSerializer class is a subclass of the HyperlinkedModelSerializer superclass. We will use the ScoreSerializer class to serialize PlayerScore instances related to a Player, that is, to display all the scores for a specific player when we serialize a Player. We want to display all the details for the related Game but we don't include the related Player because Player will use this ScoreSerializer serializer.

The ScoreSerializer class declares a game attribute as an instance of the previously coded GameSerializer class. We created the game field as a models.ForeignKey instance in the PlayerScore model and we want to serialize the same data for the game that we coded in the GameSerializer class.

The ScoreSerializer class declares a Meta inner class that declares the following two attributes:

  • model: This attribute specifies the model related to the serializer, that is, the PlayerScore class.
  • fields: This attribute specifies a tuple of the string whose values indicate the field names that we want to include in the serialization from the related model. In this case, we include both the 'url' and the 'id'. As previously explained, we don't include the 'player' field name in this tuple of string to avoid serializing the player again.
We will use PlayerSerializer as a master and ScoreSerializer as the detail.

Open the serializers.py file in the games_service/games folder and add the following lines after the last line to declare the PlayerSerializer class. The code file for the sample is included in the restful_python_2_06_01 folder, in the Django01/games-service/games/serializers.py file:

class PlayerSerializer(serializers.HyperlinkedModelSerializer): 
    scores = ScoreSerializer(many=True, read_only=True) 
    gender = serializers.ChoiceField( 
        choices=Player.GENDER_CHOICES) 
    gender_description = serializers.CharField( 
        source='get_gender_display',  
        read_only=True) 
 
    class Meta: 
         model = Player 
         fields = ( 
               'url', 
               'name', 
               'gender', 
               'gender_description', 
               'scores') 

The PlayerSerializer class is a subclass of the HyperlinkedModelSerializer superclass. We will use the PlayerSerializer class to serialize Player instances and we will use the previously declared ScoreSerializer class to serialize all the PlayerScore instances related to Player.

The PlayerSerializer class declares a scores attribute as an instance of the previously coded ScoreSerializer class. The many argument is set to True because it is a one-to-many relationship. We use the scores name that we specified as the related_name string value when we created the player field as a models.ForeignKey instance in the PlayerScore model. This way, the scores field will render each PlayerScore that belongs to the Player by using the previously declared ScoreSerializer.

The Player model declared gender as an instance of models.CharField with the choices attribute set to the Player.GENDER_CHOICES string tuple. The ScoreSerializer class declares a gender attribute as an instance of serializers.ChoiceField with the choices argument set to the Player.GENDER_CHOICES string tuple. In addition, the class declares a gender_description attribute with read_only set to True and the source argument set to 'get_gender_display'. The source string is built with get_ followed by the field name, gender, and _display. This way, the read-only gender_description attribute will render the description for the gender choices instead of the single char stored values. The ScoreSerializer class declares a Meta inner class that declares the model and fields attributes. The model attribute specifies the Player class.

Open the serializers.py file in the games_service/games folder and add the following lines after the last line to declare the PlayerScoreSerializer class. The code file for the sample is included in the restful_python_2_06_01 folder, in the Django01/games-service/games/serializers.py file:

class PlayerScoreSerializer(serializers.ModelSerializer): 
    # We want to display the players's name instead of its id 
   player = serializers.SlugRelatedField(queryset=Player.objects.all(), slug_field='name') 
   # We want to display the game's name instead of its id 
   game = serializers.SlugRelatedField(queryset=Game.objects.all(), slug_field='name') 
 
   class Meta: 
         model = PlayerScore 
         fields = ( 
               'url', 
               'id', 
               'score', 
               'score_date', 
               'player', 
               'game')

The PlayerScoreSerializer class is a subclass of the HyperlinkedModelSerializer superclass. We will use the PlayerScoreSerializer class to serialize PlayerScore instances. Previously, we created the ScoreSerializer class to serialize PlayerScore instances as the detail of a player. We will use the new PlayerScoreSerializer class when we want to display the related player's name and the related game's name. In the other serializer class, we didn't include any information related to the player and we included all the details for the game.

The PlayerScoreSerializer class declares a player attribute as an instance of serializers.SlugRelatedField with its queryset argument set to Player.objects.all() and its slug_field argument set to 'name'. We created the player field as a models.ForeignKey instance in the PlayerScore model, and we want to display the player's name as the description (slug field) for the related Player. Thus, we specified 'name' as the slug_field argument. If it is necessary to display the possible options for the related player in a form in the browsable API, Django will use the expression specified in the queryset argument to retrieve all the possible players and display their specified slug field.

The PlayerScoreSerializer class declares a game attribute as an instance of serializers.SlugRelatedField with its queryset argument set to Game.objects.all() and its slug_field argument set to 'name'. We created the game field as a models.ForeignKey instance in the PlayerScore model and we want to display the game's name as the description (slug field) for the related Game.

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

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