Taking advantage of pagination

Our database has a few rows in 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, games, and game categories, and therefore, we will have to deal with large result sets. We can take advantage of the pagination features available in Django REST Framework to make it easy to specify how we want large results sets to be split into individual pages of data.

First, we will compose and send HTTP requests to create 10 games that belong to one of the categories we have created: 2D mobile arcade. This way, we will have a total of 12 games that persist in the database. We had 2 games and we will add 10 more:

http POST :8000/games/ name='Tetris Reloaded' game_category='2D mobile arcade' played=false release_date='2016-06-21T03:02:00.776594Z'
http POST :8000/games/ name='Puzzle Craft' game_category='2D mobile arcade' played=false release_date='2016-06-21T03:02:00.776594Z'
http POST :8000/games/ name='Blek' game_category='2D mobile arcade' played=false release_date='2016-06-21T03:02:00.776594Z'
http POST :8000/games/ name='Scribblenauts Unlimited' game_category='2D mobile arcade' played=false release_date='2016-06-21T03:02:00.776594Z'
http POST :8000/games/ name='Cut the Rope: Magic' game_category='2D mobile arcade' played=false release_date='2016-06-21T03:02:00.776594Z'
http POST :8000/games/ name='Tiny Dice Dungeon' game_category='2D mobile arcade' played=false release_date='2016-06-21T03:02:00.776594Z'
http POST :8000/games/ name='A Dark Room' game_category='2D mobile arcade' played=false release_date='2016-06-21T03:02:00.776594Z'
http POST :8000/games/ name='Bastion' game_category='2D mobile arcade' played=false release_date='2016-06-21T03:02:00.776594Z'
http POST :8000/games/ name='Welcome to the Dungeon' game_category='2D mobile arcade' played=false release_date='2016-06-21T03:02:00.776594Z'
http POST :8000/games/ name='Dust: An Elysian Tail' game_category='2D mobile arcade' played=false release_date='2016-06-21T03:02:00.776594Z'

The following are the equivalent curl commands:

curl -iX POST -H "Content-Type: application/json" -d '{"name":"Tetris Reloaded", "game_category":"2D mobile arcade", "played": "false", "release_date": "2016-06-21T03:02:00.776594Z"}' :8000/games/
curl -iX POST -H "Content-Type: application/json" -d '{"name":"Puzzle Craft", "game_category":"2D mobile arcade", "played": "false", "release_date": "2016-06-21T03:02:00.776594Z"}' :8000/games/
curl -iX POST -H "Content-Type: application/json" -d '{"name":"Blek", "game_category":"2D mobile arcade", "played": "false", "release_date": "2016-06-21T03:02:00.776594Z"}' :8000/games/
curl -iX POST -H "Content-Type: application/json" -d '{"name":"Scribblenauts Unlimited", "game_category":"2D mobile arcade", "played": "false", "release_date": "2016-06-21T03:02:00.776594Z"}' :8000/games/
curl -iX POST -H "Content-Type: application/json" -d '{"name":"Cut the Rope: Magic", "game_category":"2D mobile arcade", "played": "false", "release_date": "2016-06-21T03:02:00.776594Z"}' :8000/games/
curl -iX POST -H "Content-Type: application/json" -d '{"name":"Tiny Dice Dungeon", "game_category":"2D mobile arcade", "played": "false", "release_date": "2016-06-21T03:02:00.776594Z"}' :8000/games/
curl -iX POST -H "Content-Type: application/json" -d '{"name":"A Dark Room", "game_category":"2D mobile arcade", "played": "false", "release_date": "2016-06-21T03:02:00.776594Z"}' :8000/games/
curl -iX POST -H "Content-Type: application/json" -d '{"name":"Bastion", "game_category":"2D mobile arcade", "played": "false", "release_date": "2016-06-21T03:02:00.776594Z"}' :8000/games/
curl -iX POST -H "Content-Type: application/json" -d '{"name":"Welcome to the Dungeon", "game_category":"2D mobile arcade", "played": "false", "release_date": "2016-06-21T03:02:00.776594Z"}' :8000/games/
curl -iX POST -H "Content-Type: application/json" -d '{"name":"Dust: An Elysian Tail", "game_category":"2D mobile arcade", "played": "false", "release_date": "2016-06-21T03:02:00.776594Z"}' :8000/games/

The preceding commands will compose and send ten POST HTTP requests with the specified JSON key-value pairs. The 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 a GET HTTP request to /games/. We will configure one of the customizable pagination styles included in Django REST Framework to include a maximum of five resources in each individual page of data.

Tip

Our API uses 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 gamesapi/settings.py file and add the following lines that declare a dictionary named REST_FRAMEWORK with key-value pairs that configure the global pagination settings. The code file for the sample is included in the restful_python_chapter_03_02 folder:

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

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 that indicates the maximum number of items to return and an offset that specifies the starting position of the query. The value for the PAGE_SIZE settings key specifies a global setting with the default value for the 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 the maximum limit value in order to avoid the undesired huge result sets.

Now, we will compose and send an HTTP request to retrieve all the games, specifically the following HTTP GET method to /games/:

http GET :8000/games/

The following is the equivalent curl command:

curl -iX GET :8000/games/

The generic views will use the new settings that we added to enable the offset/limit pagination and the result will provide us the first 5 game resources (results key), the total number of games for the query (count key), and a link to the next (next key) and previous (previous key) pages. In this case, the resultset is the first page, and therefore, the link to the previous page (previous key) is null. We will receive a 200 OK status code in the response header and the 5 games in the results array:

HTTP/1.0 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Date: Fri, 01 Jul 2016 00:57:55 GMT
Server: WSGIServer/0.2 CPython/3.5.1
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN
{
    "count": 12, 
    "next": "http://localhost:8000/games/?limit=5&offset=5", 
    "previous": null, 
    "results": [
        {
            "game_category": "2D mobile arcade", 
            "name": "A Dark Room", 
            "played": false, 
            "release_date": "2016-06-21T03:02:00.776594Z", 
            "url": "http://localhost:8000/games/10/"
        }, 
        {
            "game_category": "2D mobile arcade", 
            "name": "Bastion", 
            "played": false, 
            "release_date": "2016-06-21T03:02:00.776594Z", 
            "url": "http://localhost:8000/games/11/"
        }, 
        {
            "game_category": "2D mobile arcade", 
            "name": "Blek", 
            "played": false, 
            "release_date": "2016-06-21T03:02:00.776594Z", 
            "url": "http://localhost:8000/games/6/"
        }, 
        {
            "game_category": "2D mobile arcade", 
            "name": "Cut the Rope: Magic", 
            "played": false, 
            "release_date": "2016-06-21T03:02:00.776594Z", 
            "url": "http://localhost:8000/games/8/"
        }, 
        {
            "game_category": "2D mobile arcade", 
            "name": "Dust: An Elysian Tail", 
            "played": false, 
            "release_date": "2016-06-21T03:02:00.776594Z", 
            "url": "http://localhost:8000/games/13/"
        }
    ]
}

In the preceding HTTP request, we didn't specify any value for either the limit or offset parameters. However, as we specified the default value of limit as 5 items in the global settings, the generic views use this configuration value and provide us with the first page. If we compose and send the following HTTP request to retrieve the first page of all the games by specifying 1 for the offset value, the API will provide the same results shown before:

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

The following is the equivalent curl command:

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

If we compose and send the following HTTP request to retrieve the first page of all the games by specifying 0 for the offset value and 5 for the limit, the API will also provide the same results as shown earlier:

http GET ':8000/games/?limit=5&offset=0'

The following is the equivalent curl command:

curl -iX GET ':8000/games/?limit=5&offset=0'

Now, we will compose and send an HTTP 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 5. 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:

http GET ':8000/games/?limit=5&offset=5'

The following is the equivalent curl command:

curl -iX GET ':8000/games/?limit=5&offset=5'

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

HTTP/1.0 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Date: Fri, 01 Jul 2016 01:25:10 GMT
Server: WSGIServer/0.2 CPython/3.5.1
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN
{
    "count": 12, 
    "next": "http://localhost:8000/games/?limit=5&offset=10", 
    "previous": "http://localhost:8000/games/?limit=5", 
    "results": [
        {
            "game_category": "2D mobile arcade", 
            "name": "Puzzle Craft", 
            "played": false, 
            "release_date": "2016-06-21T03:02:00.776594Z", 
            "url": "http://localhost:8000/games/5/"
        }, 
        {
            "game_category": "3D RPG", 
            "name": "PvZ Garden Warfare 4", 
            "played": true, 
            "release_date": "2016-06-21T03:02:00.776594Z", 
            "url": "http://localhost:8000/games/2/"
        }, 
        {
            "game_category": "2D mobile arcade", 
            "name": "Scribblenauts Unlimited", 
            "played": false, 
            "release_date": "2016-06-21T03:02:00.776594Z", 
            "url": "http://localhost:8000/games/7/"
        }, 
        {
            "game_category": "3D RPG", 
            "name": "Superman vs Aquaman", 
            "played": true, 
            "release_date": "2016-06-21T03:02:00.776594Z", 
            "url": "http://localhost:8000/games/3/"
        }, 
        {
            "game_category": "2D mobile arcade", 
            "name": "Tetris Reloaded", 
            "played": false, 
            "release_date": "2016-06-21T03:02:00.776594Z", 
            "url": "http://localhost:8000/games/4/"
        }
    ]
}

In the preceding HTTP request, we specified values for both the limit and offset parameters. However, as we specified the default value of limit in 5 items in the global settings, the following request will produce the same results than the previous request:

http GET ':8000/games/?offset=5'

The following is the equivalent curl command:

curl -iX GET ':8000/games/?offset=5'

Finally, we will compose and send an HTTP 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 10. 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:

http GET ':8000/games/?limit=5&offset=10'

The following is the equivalent curl command:

curl -iX GET ':8000/games/?limit=5&offset=10'

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

HTTP/1.0 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Date: Fri, 01 Jul 2016 01:28:13 GMT
Server: WSGIServer/0.2 CPython/3.5.1
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN
{
    "count": 12, 
    "next": null, 
    "previous": "http://localhost:8000/games/?limit=5&offset=5", 
    "results": [
        {
            "game_category": "2D mobile arcade", 
            "name": "Tiny Dice Dungeon", 
            "played": false, 
            "release_date": "2016-06-21T03:02:00.776594Z", 
            "url": "http://localhost:8000/games/9/"
        }, 
        {
            "game_category": "2D mobile arcade", 
            "name": "Welcome to the Dungeon", 
            "played": false, 
            "release_date": "2016-06-21T03:02:00.776594Z", 
            "url": "http://localhost:8000/games/12/"
        }
    ]
}
..................Content has been hidden....................

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