Round 7: Django Application

  1. Preamble
  2. Models
  3. Views
  4. Templates

Preamble

In this exercise round, you will complete a small web service that provides country and continent information. This information will be available via simple HTTP API where the data can be fetched in JSON format. Users can browse the data in a separate HTML and JavaScript based user interface.

You are given a started Django project including two incomplete applications. In first exercise, you will define models and import initial data given to you. Then in second exercise, you will complete the API views that handle serving this data. And finally in third exercise, you will create templates for humans to browse this data that will utilize components created in first two exercises.

Note that tests are given to you to help with the exercises. However, it is also useful to test your code in browser with Django's development server.

1. Models

In this exercise, you need to implement models for Continent and Country. An XML file country/countrydata/fixtures/countrydata.xml* is given that defines the contents for your database.
* The data in this exercise is licensed under a Creative Commons Attribution License and downloaded from GeoNames.org.

You must define appropriate models to hold the data. Then, create SQLite database from the new models. Finally, load the given data from the countrydata.xml file by using loaddata.

Getting Started

1. Open the XML file and examine the data. In the beginning of the XML file you should find the continents followed by the countries. From the data you can easily deduce most of the requirements for the models, such as the names and types of the fields. Additional requirements for the models (not deducible from the data) are:

2. Implement the models and makemigrations and migrate the database.

3. Finally, load the data into the database using the loaddata command.

If you installed Django in a virtualenv on Linux or OS X, remember to activate the virtualenv before using manage.py.

Things to read

If you run into problems or don't know where to start, the following resources might be helpful:

What to Submit?

In this exercise you must submit your implementation of the Continent and Country models in the models.py.

Before submitting, you should test your program yourself. We provide you with some Django tests: country/countrydata/tests.py. Refer to the first Django round for instructions how to run the tests. Please note that the tests.py contains two tests classes, one for each exercise on this round. Thus, after solving this exercise, only the tests from class BasicDataTestCase should pass. Hint: you can run a single named test case separately.

$ python manage.py test countrydata.tests.BasicDataTestCase

The provided project has also the automatic administration interface configured. You may take a look at your objects in the admin interface if you create a superuser in the shell.

$ python manage.py createsuperuser

To properly list the model objects, the __str__-function needs to be implemented.

Submitting Your Project to Plussa

Add, commit and push your new files and possible changes to the Git as in round 1. Finally, just copy and paste your GitLab project's URL to Plussa. The file we will check is exercises/07_django/country/countrydata/models.py.

2. Views

Rendering JSON in Django Views

In this exercise you need to implement the views, continent_json and country_json, that will return data for countries and continents in JSON format with JSONP support. You should continue working with the same Django project that you already worked with in the first exercise of this Django round. Your views will use the Country and Continent models that you implemented.

Constructing JSON string

You need to turn the country data in the models to JSON. One way to do it, would be to store the data in corresponding python data structures (dicts and lists) and to use the json module to encode it to JSON string. The json function dumps does just this. See the Examples below for how the data should be formatted.

Making the view render JSON instead of HTML

The HttpResponse objects that views return are not just for carrying HTML. The body of an HTTP response may carry any text or data that is encoded in text. But if you return something else than HTML, you should set the mimetype of the data in the HttpResponse. For JSON data this would be:
return HttpResponse(my_json_data, content_type="application/json"). There is also JsonResponse in Django.

If a continent or country with the given code is not found, the view should respond with an HTTP response having the 404 status code.

About JSONP

Make sure you understand what JSONP is and why we need it (see Things to Read below). If the HTTP GET request for continent_json or country_json has the callback GET parameter, the JSON data must be wrapped in a JavaScript function call and the name of the function must be the value of the callback. If there is no callback parameter, the views should return normal JSON.

Examples

Example of the rendered JSON for the url
http://localhost:8000/api/eu/fi.json:

{
  "area": 337030,
  "population": 5244000,
  "capital": "Helsinki"
}
        

Example of the rendered JSON for the url
http://localhost:8000/api/eu/fi.json?callback=myCallbackFunction (with JSONP callback):

myCallbackFunction({
  "area": 337030,
  "population": 5244000,
  "capital": "Helsinki"
})
        

Example of the rendered JSON for the url
http://localhost:8000/api/eu.json?callback=myCallbackFunction:

myCallbackFunction({
  "xk": "Kosovo",
  "ch": "Switzerland",
  "gr": "Greece",
  "va": "Vatican City",
  "ee": "Estonia",
  "is": "Iceland",
  "al": "Albania",
  "gg": "Guernsey",
  "cz": "Czech Republic",
  "cy": "Cyprus",
  "sj": "Svalbard and Jan Mayen",
  "im": "Isle of Man",
  "at": "Austria",
  "je": "Jersey",
  "ad": "Andorra",
  "ax": "\u00c5land Islands",
  "ie": "Ireland",
  "gi": "Gibraltar",
  "dk": "Denmark",
  "ru": "Russia",
  "nl": "Netherlands",
  "pt": "Portugal",
  "no": "Norway",
  "li": "Liechtenstein",
  "lv": "Latvia",
  "lt": "Lithuania",
  "lu": "Luxembourg",
  "es": "Spain",
  "it": "Italy",
  "ro": "Romania",
  "pl": "Poland",
  "be": "Belgium",
  "fr": "France",
  "bg": "Bulgaria",
  "ba": "Bosnia and Herzegovina",
  "hr": "Croatia",
  "de": "Germany",
  "hu": "Hungary",
  "fi": "Finland",
  "by": "Belarus",
  "cs": "Serbia and Montenegro",
  "fo": "Faroe Islands",
  "me": "Montenegro",
  "md": "Moldova",
  "mc": "Monaco",
  "rs": "Serbia",
  "mk": "Macedonia",
  "sk": "Slovakia",
  "mt": "Malta",
  "si": "Slovenia",
  "sm": "San Marino",
  "ua": "Ukraine",
  "se": "Sweden",
  "gb": "United Kingdom"
})

Things to Read

Here are some external resources to help you out with this exercise:

Submitting Your Project to Plussa

Add, commit and push your new files and possible changes to the Git as in round 1. Finally, just copy and paste your GitLab project's URL to Plussa. The file we will check is exercises/07_django/country/countrydata/views.py.

3. Templates

Templates and views for normal requests

In this exercise, you need to implement templates that will display countries and their data in a table on the bottom of this page. The table should only be visible when a user has requested this view with a country code. Above the table there should be links to all continents in the database. If the user requests a page with a non existent continent code a 404 HTTP response code should be returned.

Templates and (changes to) views for Ajax updates

The base template and a piece of javascript that come with the exercise package will make interface improvements for this page : The continent names that link to the country tables of other continents are modified by the script so that instead of reloading the whole page, they trigger an Ajax request. This will only update the modified part of the page (ie. the table). The JavaScript code used is included in the given material. In this exercise you don't need to do the javascript, but to write the views that provide Ajax call the requested data .

You need to modify the view (show_continent) on server side so that when it is requested with an Ajax request, it will only render the table template (selectui/countrytable.html) instead of the whole page.

Checking whether a request is made via Ajax can be checked from information in the HttpRequest object using the is_ajax()-method.

The Templates

The given material contains an index.html template in country/selectui/templates/selectui. Do not modify this! Instead, write your part of the page to the templates countrytable.html and continentmenu.html that are included into the index.html.

Template countrytable

The template countrytable should render a table with columns for Name, Capital, Population, and Area for all countries of the continent passed to the template. If no continent is passed, it should simply render the headings of the table. Example for imaginary continent with only one country:

<table id="countryTable">
  <thead>
    <tr>
      <th>Name</th>
      <th>Capital</th>
      <th>Population</th>
      <th>Area</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Sweden</td>
      <td>Stockholm</td>
      <td>9045000</td>
      <td>449964 km2</td>
    </tr>
  </tbody>
</table>

Template continentmenu

The template should render an unordered list with list items including links to the continents passed to the template (as template variable all_continents). Example with only one continent:

<ul id="continentMenu">
  <li><a href="insert-path-to-continent-using-the-template">Scandinavia</a></li>
</ul>

Hints and Tips

Submitting Your Project to Plussa

Add, commit and push your new files and possible changes to the Git as in round 1. Finally, just copy and paste your GitLab project's URL to Plussa. The files we will check are views.py, countrytable.html, and continentmenu.html in exercises/07_django.