Dynamic data in templates

Part of this chapter is based on tutorials by Django Girls Tutorial : https://tutorial.djangogirls.org

We have different pieces in place: the Player model is defined in models.py, we have index in views.py and the template added. But how will we actually make our posts appear in our HTML template? Because that is what we want to do – take some content (models saved in the database) and display it nicely in our template, right?

This is exactly what views are supposed to do: connect models and templates. In our index view we will need to take the models we want to display and pass them to the template. In a view we decide what (model) will be displayed in a template.

OK, so how will we achieve this?

We need to open our myfirstgame/views.py. So far index view looks like this:

from django.shortcuts import render

def index(request):
    return render(request, 'myfirstgame/index.html', {})

Remember when we talked about including code written in different files? Now is the moment when we have to include the model we have written in models.py. We will add the line from .models import Player like this:

from django.shortcuts import render

from .models import Player

The dot before models means current directory or current application. Both views.py and models.py are in the same directory. This means we can use . and the name of the file (without .py). Then we import the name of the model (Player).

But what's next? To take actual player entries from the Player model we need something called QuerySet.

QuerySet

You should already be familiar with how QuerySets work. We talked about them in the previous chapter.

So now we want published player entries sorted by game_end, right? We already did that in QuerySets chapter!

Player.objects.filter(game_end__lte=timezone.now()).order_by("game_end")

Now we put this piece of code inside the myfirstgame/views.py file by adding it to the function def index(request), but don't forget to first add from django.utils import timezone:

from django.shortcuts import render
from django.utils import timezone

from .models import Player

def index(request):
    players = Player.objects.filter(game_end__lte=timezone.now()).order_by("game_end")
    return render(request, 'myfirstgame/index.html', {})

The last missing part is passing the players QuerySet to the template context. Don't worry – we will cover how to display it in a later chapter.

Please note that we create a variable for our QuerySet: players. Treat this as the name of our QuerySet. From now on we can refer to it by this name.

In the render function we have one parameter request (everything we receive from the user via the Internet) and another giving the template file ('myfirstgame/index.html'). The last parameter, {}, is a place in which we can add some things for the template to use. We need to give them names (we will stick to 'players' right now). :) It should look like this: {'players': players}. Please note that the part before : is a string; you need to wrap it with quotes: ''.

So finally our myfirstgame/views.py file should look like this:

from django.shortcuts import render
from django.utils import timezone

from .models import Player

def index(request):
    players = Player.objects.filter(game_end__lte=timezone.now()).order_by("game_end")
    return render(request, 'myfirstgame/index.html', {'players':players})

That's it! Time to go back to our template in myfirstgame/templates/myfirstgame/index.html and display this QuerySet!

Want to read a little bit more about QuerySets in Django? You should look here: https://docs.djangoproject.com/en/2.0/ref/models/querysets/

Django templates (again)

Time to display some data! Django gives us some helpful built-in template tags for that.

What are template tags?

You see, in HTML, you can't really write Python code, because browsers don't understand it. They know only HTML. We know that HTML is rather static, while Python is much more dynamic.

Django template tags allow us to transfer Python-like things into HTML, so you can build dynamic websites faster. Cool!

Display players list template

In the previous chapter we gave our template a list of posts in the players variable. Now we will display it in HTML.

To print a variable in Django templates, we use double curly brackets with the variable's name inside, like this:

In myfirstgame/templates/myfirstgame/index.html, add <p>{{ players }}</p> in between <body> </body>:

<!DOCTYPE html>
<html>
  <head>
    <title>Welcome to Text-Based Adventure Game in Django</title>
  </head>
  <body>
    <h1>Welcome to Text-Based Adventure Game in Django</h1>
    <h2>Come back soon when we add more functionality</h2>
    <p>This is a <em>choose your own adventure game</em>.</p>
    <p>{{ players }}</p>
  </body>
</html>

Save the file, and go to http://127.0.0.1:8000/ to see the results. It should be like the following:

This means that Django understands it as a list of objects. We can display the items in the list with for loops! In a Django template, this is how you do it, modify the entry with <p>{{ players }}</p> to the following:

<p>
    {% for player in players %}
        {{ player }}
    {% endfor %}
</p>

Save the file and go to http://127.0.0.1:8000/ to see the results. It should be like the following:

It works! But we want the posts to be displayed like the static entries, you can mix HTML and template tags. Our body will look like this:

<!DOCTYPE html>
<html>
  <head>
    <title>Welcome to Text-Based Adventure Game in Django</title>
  </head>
  <body>
    <h1>Welcome to Text-Based Adventure Game in Django</h1>
    <h2>Come back soon when we add more functionality</h2>
    <p>This is a <em>choose your own adventure game</em>.</p>
    <div>
        <h3>List of players in order of latest who played</h3>
        <ul>
        {% for player in players %}
            <li>Name: {{ player.name }} - Game Over on <em>{{ player.game_end }}</em></li>
        {% endfor %}
        </ul>
    </div>
  </body>
</html>

Everything you put between {% for %} and {% endfor %} will be repeated for each object in the list.

Save the file and go to http://127.0.0.1:8000/ to see the results. It should be like the following:

Have you noticed that we used a slightly different notation this time ({{ player.name }} or {{ player.game_end }})? We are accessing data in each of the fields defined in our Player model.

One more thing

Don't forget to commit your code!

$ git status
[...]
$ git add --all .
$ git status
[...]
$ git commit -m "Modified templates to display posts from database."
[...]

Works like a charm? We're proud! Step away from your computer for a bit – you have earned a break. :)

results matching ""

    No results matching ""