Taking advantage of pagination

Our database has a few rows for each of the tables that persist the models we have defined. However, after we start working with our API in a real-life production environment, we will have thousands of player scores, players, and games—although the ESRB ratings will still be few in number. We definitely have to prepare our API to deal with large result sets. Luckily, we can take advantage of the pagination features available in Django REST framework to make it easy to specify how we want large result sets to be split into individual pages of data.

First, we will write commands to compose and send HTTP POST requests to create 10 games that belong to one of the ESRB ratings we have created: T (Teen). This way, we will have a total of 12 games persisted in the database. We had two games and we add 10 more. The code file for the sample is included in the restful_python_2_07_01 folder, in the Django01/cmd/cmd705.txt file:

http POST ":8000/games/" name='Heavy Fire: Red Shadow' esrb_rating='T (Teen)' release_date='2018-06-21T03:02:00.776594Z'
http POST ":8000/games/" name='ARK: Survival Evolved' esrb_rating='T (Teen)' release_date='2018-06-21T03:02:00.776594Z'
http POST ":8000/games/" name='The Escapists 2' esrb_rating='T (Teen)' release_date='2018-06-21T03:02:00.776594Z'
http POST ":8000/games/" name='Honor and Duty: D-Day' esrb_rating='T (Teen)' release_date='2018-06-21T03:02:00.776594Z'
http POST ":8000/games/" name='Speed Brawl' esrb_rating='T (Teen)' release_date='2018-06-21T03:02:00.776594Z'
http POST ":8000/games/" name='Unearthing Mars 2' esrb_rating='T (Teen)' release_date='2018-06-21T03:02:00.776594Z'
http POST ":8000/games/" name='Super Street: The Game' esrb_rating='T (Teen)' release_date='2019-01-21T03:02:00.776594Z'
http POST ":8000/games/" name='Valkyria Chronicles 4' esrb_rating='T (Teen)' release_date='2019-01-21T03:02:00.776594Z'
http POST ":8000/games/" name='Tales of Vesperia: Definitive Edition' esrb_rating='T (Teen)' release_date='2019-01-21T03:02:00.776594Z'
http POST ":8000/games/" name='Moonfall Ultimate' esrb_rating='T (Teen)' release_date='2019-01-21T03:02:00.776594Z'

The following are the equivalent curl commands. The code file for the sample is included in the restful_python_2_07_01 folder, in the Django01/cmd/cmd706.txt file:

curl -iX POST -H "Content-Type: application/json" -d '{"name":"Heavy Fire: Red Shadow", "esrb_rating":"T (Teen)", "release_date": "2018-06-21T03:02:00.776594Z"}' 
"localhost:8000/games/"
curl -iX POST -H "Content-Type: application/json" -d '{"name":"ARK: Survival Evolved", "esrb_rating":"T (Teen)", "release_date": "2018-06-21T03:02:00.776594Z"}'
"localhost:8000/games/"
curl -iX POST -H "Content-Type: application/json" -d '{"name":"The Escapists 2", "esrb_rating":"T (Teen)", "release_date": "2018-06-21T03:02:00.776594Z"}'
"localhost:8000/games/"
curl -iX POST -H "Content-Type: application/json" -d '{"name":"Honor and Duty: D-Day", "esrb_rating":"T (Teen)", "release_date": "2018-06-21T03:02:00.776594Z"}'
"localhost:8000/games/"
curl -iX POST -H "Content-Type: application/json" -d '{"name":"Speed Brawl", "esrb_rating":"T (Teen)", "release_date": "2018-06-21T03:02:00.776594Z"}'
"localhost:8000/games/"
curl -iX POST -H "Content-Type: application/json" -d '{"name":"Unearthing Mars 2", "esrb_rating":"T (Teen)", "release_date": "2018-06-21T03:02:00.776594Z"}'
"localhost:8000/games/"
curl -iX POST -H "Content-Type: application/json" -d '{"name":"Super Street: The Game", "esrb_rating":"T (Teen)", "release_date": "2019-01-21T03:02:00.776594Z"}'
"localhost:8000/games/"
curl -iX POST -H "Content-Type: application/json" -d '{"name":"Valkyria Chronicles 4", "esrb_rating":"T (Teen)", "release_date": "2019-01-21T03:02:00.776594Z"}'
"localhost:8000/games/"
curl -iX POST -H "Content-Type: application/json" -d '{"name":"Tales of Vesperia: Definitive Edition", "esrb_rating":"T (Teen)", "release_date": "2019-01-21T03:02:00.776594Z"}'
"localhost:8000/games/"
curl -iX POST -H "Content-Type: application/json" -d '{"name":"Moonfall Ultimate", "esrb_rating":"T (Teen)", "release_date": "2019-01-21T03:02:00.776594Z"}'
"localhost:8000/games/"

The previous commands will compose and send 10 HTTP POST requests with the specified JSON key-value pairs. Each request specifies /games/, and therefore, it will match '^games/$' and run the post method for the views.GameList class-based view.

Now we have 12 games in our database. However, we don't want to retrieve the 12 games when we compose and send an HTTP GET request to /games/. We will configure one of the customizable pagination styles included in Django REST framework to include a maximum of four resources in each individual page of data.

Our API is using the generic views that work with the mixin classes that can handle paginated responses, and therefore, they will automatically take into account the pagination settings we configure in Django REST Framework.

Open the settings.py file in the games_service/games_service folder. Add the following lines after the last line to declare a dictionary named REST_FRAMEWORK with key-value pairs that configure the global pagination settings for Django REST Framework. The code file for the sample is included in the restful_python_2_07_02 folder, in the Django01/games-service/games_service/settings.py file:

REST_FRAMEWORK = { 
    'DEFAULT_PAGINATION_CLASS': 
    'rest_framework.pagination.LimitOffsetPagination', 
    'PAGE_SIZE': 4 
} 

The value for the DEFAULT_PAGINATION_CLASS settings key specifies a global setting with the default pagination class that the generic views will use to provide paginated responses. In this case, we will use the rest_framework.pagination.LimitOffsetPagination class that provides a limit/offset based style. This pagination style works with limit, which indicates the maximum number of items to return, and offset, which specifies the starting position of the query. The value for the PAGE_SIZE settings key specifies a global setting with the default value for limit, also known as page size. We can specify a different limit when we perform the HTTP request by specifying the desired value in the limit query parameter. We can configure the class to have a maximum limit value in order to avoid undesired huge result sets.

Now run the following command to compose and send an HTTP GET request to retrieve all the games; specifically, an HTTP GET method to /games/. The code file for the sample is included in the restful_python_2_07_02 folder, in the Django01/cmd/cmd707.txt file:

    http GET ":8000/games/"

The following is the equivalent curl command. The code file for the sample is included in the restful_python_2_07_02 folder, in the Django01/cmd/cmd708.txt file:

    curl -iX GET "localhost:8000/games/"

The generic views will use the new settings we added to enable the offset/limit pagination. We will receive a 200 OK status code in the response header and the result will provide us values for the following keys:

  • results: The value for this key provides the first four-game resources.
  • count: The value for this key provides the total number of games for the query. In this case, the value is the total number of games persisted in the database because the query didn't apply any filter criteria.
  • next: The value for this key provides the URL for the next page.
  • previous: The value for this key provides the URL for the previous page. In this case, the result set is the first page, and therefore, the link to the previous page is null.

The output of the curl command is shown as follows:

    HTTP/1.1 200 OK
    Allow: GET, POST, HEAD, OPTIONS
    Content-Length: 812
    Content-Type: application/json
    Date: Fri, 26 Oct 2018 19:33:50 GMT
    Server: WSGIServer/0.2 CPython/3.7.1
    Vary: Accept, Cookie
    X-Frame-Options: SAMEORIGIN
    
    {
        "count": 12,
        "next": "http://localhost:8000/games/?limit=4&offset=4",
        "previous": null,
        "results": [
            {
                "esrb_rating": "T (Teen)",
                "name": "ARK: Survival Evolved",
                "played_once": false,
                "played_times": 0,
                "release_date": "2018-06-21T03:02:00.776594Z",
                "url": "http://localhost:8000/games/4/"
            },
            {
                "esrb_rating": "AO (Adults Only)",
                "name": "Battlefield V",
                "played_once": false,
                "played_times": 0,
                "release_date": "2017-05-01T01:02:00.776594Z",
                "url": "http://localhost:8000/games/1/"
            },
            {
                "esrb_rating": "T (Teen)",
                "name": "Heavy Fire: Red Shadow",
                "played_once": false,
                "played_times": 0,
                "release_date": "2018-06-21T03:02:00.776594Z",
                "url": "http://localhost:8000/games/3/"
            },
            {
                "esrb_rating": "T (Teen)",
                "name": "Honor and Duty: D-Day",
                "played_once": false,
                "played_times": 0,
                "release_date": "2018-06-21T03:02:00.776594Z",
                "url": "http://localhost:8000/games/6/"
            }
        ]
    }
  

In the previous HTTP GET request, we didn't specify any values for either the limit or offset parameters. However, as we specified the default value for the limit as 4 in the pagination settings, the generic views use this configuration value and provide us with the first page. If we compose and send the following HTTP GET request to retrieve the first page of all the games by specifying 0 for the offset value, the API will provide the same results shown before. Notice that offset is zero-based. The code file for the sample is included in the restful_python_2_07_02 folder, in the Django01/cmd/cmd709.txt file:

    http GET ":8000/games/?offset=0"

The following is the equivalent curl command. The code file for the sample is included in the restful_python_2_07_02 folder, in the Django01/cmd/cmd710.txt file:

    curl -iX GET "localhost:8000/games/?offset=0"

If we compose and send the following HTTP GET request to retrieve the first page of all the games by specifying 0 for the offset value and 4 for limit, the API will also provide the same results shown before. The code file for the sample is included in the restful_python_2_07_02 folder, in the Django01/cmd/cmd711.txt file:

    http GET ":8000/games/?limit=4&offset=0"

The following is the equivalent curl command. The code file for the sample is included in the restful_python_2_07_02 folder, in the Django01/cmd/cmd712.txt file:

    curl -iX GET "localhost:8000/games/?limit=4&offset=0"

Now we will compose and send an HTTP GET request to retrieve the next page, that is, the second page for the games, specifically an HTTP GET method to /games/ with the offset value set to 4. Remember that the value for the next key returned in the JSON body of the previous result provides us with the URL to the next page. The following is the equivalent curl command. The code file for the sample is included in the restful_python_2_07_02 folder, in the Django01/cmd/cmd713.txt file:

    http GET ":8000/games/?limit=4&offset=4"

The following is the equivalent curl command. The following is the equivalent curl command. The code file for the sample is included in the restful_python_2_07_02 folder, in the Django01/cmd/cmd714.txt file:

    curl -iX GET ":8000/games/?limit=4&offset=4"

The result will provide us the second set of 4 game resources in the results key, the total number of games for the query in the count key and a link to the next and previous pages in the next and previous keys. In this case, the result set is the second page, and therefore, the link to the previous page in the previous key is http://localhost:8000/games/?limit=4. We will receive a 200 OK status code in the response header and the four games in the results array:

    HTTP/1.1 200 OK
    Allow: GET, POST, HEAD, OPTIONS
    Content-Length: 859
    Content-Type: application/json
    Date: Fri, 26 Oct 2018 20:25:52 GMT
    Server: WSGIServer/0.2 CPython/3.7.1
    Vary: Accept, Cookie
    X-Frame-Options: SAMEORIGIN
    
    {
        "count": 12,
        "next": "http://localhost:8000/games/?limit=4&offset=8",
        "previous": "http://localhost:8000/games/?limit=4",
        "results": [
            {
                "esrb_rating": "T (Teen)",
                "name": "Moonfall Ultimate",
                "played_once": false,
                "played_times": 0,
                "release_date": "2019-01-21T03:02:00.776594Z",
                "url": "http://localhost:8000/games/12/"
            },
            {
                "esrb_rating": "AO (Adults Only)",
                "name": "Mutant Football League: Dynasty Edition",
                "played_once": true,
                "played_times": 10,
                "release_date": "2018-10-20T03:02:00.776594Z",
                "url": "http://localhost:8000/games/2/"
            },
            {
                "esrb_rating": "T (Teen)",
                "name": "Speed Brawl",
                "played_once": false,
                "played_times": 0,
                "release_date": "2018-06-21T03:02:00.776594Z",
                "url": "http://localhost:8000/games/7/"
            },
            {
                "esrb_rating": "T (Teen)",
                "name": "Super Street: The Game",
                "played_once": false,
                "played_times": 0,
                "release_date": "2019-01-21T03:02:00.776594Z",
                "url": "http://localhost:8000/games/9/"
            }
        ]
    }
  

In the previous HTTP request, we specified values for both the limit and offset parameters. However, as we specified the default value of limit as 4 in the global settings, the following request will produce the same results as the previous request. The code file for the sample is included in the restful_python_2_07_02 folder, in the Django01/cmd/cmd715.txt file:

    http GET ":8000/games/?offset=4"

The following is the equivalent curl command. The code file for the sample is included in the restful_python_2_07_02 folder, in the Django01/cmd/cmd716.txt file:

    curl -iX GET "localhost:8000/games/?offset=4"

Finally, we will write a command to compose and send an HTTP GET request to retrieve the last page, that is, the third page for the games, specifically an HTTP GET method to /games/ with the offset value set to 8. Remember that the value for the next key returned in the JSON body of the previous result provides us with the URL to the next page. The code file for the sample is included in the restful_python_2_07_02 folder, in the Django01/cmd/cmd717.txt file:

    http GET ":8000/games/?limit=4&offset=8"

The following is the equivalent curl command. The code file for the sample is included in the restful_python_2_07_02 folder, in the Django01/cmd/cmd718.txt file:

    curl -iX GET "localhost:8000/games/?limit=4&offset=8"

The result will provide us the last set with the last 4 game resources in the results key, the total number of games for the query in the count key, and a link to the next and previous pages in the next and previous keys. In this case, the result set is the last page, and therefore, the link to the next page in the next key is null. We will receive a 200 OK status code in the response header and the last four games in the results array:

    HTTP/1.1 200 OK
    Allow: GET, POST, HEAD, OPTIONS
    Content-Length: 819
    Content-Type: application/json
    Date: Fri, 26 Oct 2018 20:33:08 GMT
    Server: WSGIServer/0.2 CPython/3.7.1
    Vary: Accept, Cookie
    X-Frame-Options: SAMEORIGIN
    
    {
        "count": 12,
        "next": null,
        "previous": "http://localhost:8000/games/?limit=4&offset=4",
        "results": [
            {
                "esrb_rating": "T (Teen)",
                "name": "Tales of Vesperia: Definitive Edition",
                "played_once": false,
                "played_times": 0,
                "release_date": "2019-01-21T03:02:00.776594Z",
                "url": "http://localhost:8000/games/11/"
            },
            {
                "esrb_rating": "T (Teen)",
                "name": "The Escapists 2",
                "played_once": false,
                "played_times": 0,
                "release_date": "2018-06-21T03:02:00.776594Z",
                "url": "http://localhost:8000/games/5/"
            },
            {
                "esrb_rating": "T (Teen)",
                "name": "Unearthing Mars 2",
                "played_once": false,
                "played_times": 0,
                "release_date": "2018-06-21T03:02:00.776594Z",
                "url": "http://localhost:8000/games/8/"
            },
            {
                "esrb_rating": "T (Teen)",
                "name": "Valkyria Chronicles 4",
                "played_once": false,
                "played_times": 0,
                "release_date": "2019-01-21T03:02:00.776594Z",
                "url": "http://localhost:8000/games/10/"
            }
        ]
    }
  
..................Content has been hidden....................

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