.. _templates-label: Templates and Static Media ========================== In this chapter, we'll be extending your knowledge of Django by introducing you to the template engine as well as how to serve *static media* within your web pages. .. _model-setup-templates-label: Using Templates --------------- Up to this point, you have plugged a few things together to create a Django-powered webpage. This is coupled a view, which is in turn coupled with a series of URL mappings. Here we will delve into how to combine templates into the mix. Well-designed websites use a lot of repetition in their structure or layout. Whether you see a common header or footer on a website's pages, the `repetition of page layouts `_ aids users with navigation, promotes organisation of the website and reinforces a sense of continuity. Django provides `templates `_ to make it easier for developers to achieve this design goal, as well as separating application logic from presentational concerns. In this chapter, you'll create a basic template which will be used to create a HTML page. This template will then be dispatched via a Django view. In Chapter :ref:`model-using-label`, we will take this a step further by using templates in conjunction with models to dispatch dynamically generated data. Configuring the Templates Directory ................................... To get templates up and running, you will need to setup a directory in which template files are stored. In your Django project's directory (e.g. ``/tango_with_django_project/``), create a new directory called ``templates``. Within the new templates directory, create another directory called ``rango``. So the directory ``/tango_with_django_project/templates/rango/`` will be the location in which we will be storing templates associated with our ``rango`` application. To tell your Django project where the templates will be housed, open your project's ``settings.py`` file. Find the tuple ``TEMPLATE_DIRS`` and add in the path to your newly created ``templates`` directory, so it looks like the following example. .. code-block:: python TEMPLATE_DIRS = ( # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. '/tango_with_django_project/templates/', ) Note that you are *required to use absolute paths* to locate the ``templates`` directory. If you are part of a team or working on different computers, this may become a problem in the future. You'll have different usernames, meaning different paths to your ```` directory. The *hard-coded* path you entered above would not be the same on different computers. Of course, you could add in the template directory for each different setup, but that would be a pretty nasty way to tackle the problem. So, what can we do? .. warning:: The road to hell is paved with hard-coded paths. `Hard-coding `_ paths is considered to be a `software engineering anti-pattern `_, and will make your project less `portable `_. Dynamic Paths ............. The solution to the problem of hard-coding paths is to make use of built-in Python functions to work out the path of our ``templates`` directory automatically for us. This way, an absolute path can be obtained regardless of where you place your Django project's code on your filesystem. This in turn means that your project's code becomes more *portable.* At the expense of a little bit more complexity in setting up your Django project now, you can make your life much easier later on. No pain, no gain! To start, modify the ``settings.py`` file to include a variable called ``SETTINGS_DIR``. This will store the path to the directory in which your project's ``settings.py`` module will be contained. This is obtained by using the special Python ``__file__`` attribute, which is `set to the absolute path of your settings module `_. We then take the absolute path to the settings file, extracting the path to the directory in which the settings module is contained. For example, calling ``os.path.dirname()`` on the absolute path of ``/tango_with_django_project/tango_with_django_project/settings.py`` would yield a directory of ``/tango_with_django_project/tango_with_django_project/``. To implement this functionality, add the following code to the top of ``settings.py``. Note the importing of the ``os`` module. .. code-block:: python import os SETTINGS_DIR = os.path.dirname(__file__) Now that we have the absolute path to our project's configuration directory, we need to get the root directory of our project. This is exactly one level up from the project configuration directory. We can therefore make use of the `pardir `_ string within the Python ``os`` module to help us obtain the path to the `parent directory `_. A project configuration directory path of ``/tango_with_django_project/tango_with_django_project/`` would for example return the path ``/tango_with_django_project/``. Add the following two lines to ``settings.py`` directly underneath what you entered above. .. code-block:: python PROJECT_PATH = os.path.join(SETTINGS_DIR, os.pardir) PROJECT_PATH = os.path.abspath(PROJECT_PATH) First, we use the ``os.path.join()`` function to join together our ``SETTINGS_DIR`` variable and the ``os.pardir`` string. Typically, this will return ``/tango_with_django_project/tango_with_django_project/..``. Calling ``os.path.abspath()`` on that path will then yield the absolute path to the next directory up the hierarchy, which would be ``/tango_with_django_project/`` in our example. In other words, ``PROJECT_PATH`` now contains the absolute path to our Django project's root. We can then use this path to point to special directories in our project, such as the directory which stores our templates! .. warning:: When joining or concatenating system paths together, using ``os.path.join()`` is the preferred approach. Using this function ensures that the correct slashes are used depending on your operating system. On a POSIX-compatible operating system, forward slashes would be used to separate directories, whereas a Windows operating system would use backward slashes. If you manually append slashes to paths, you may end up with path errors when attempting to run your code on a different operating system. Let's make use of it now. Create a new variable in ``settings.py`` called ``TEMPLATE_PATH`` and store the path to the ``templates`` directory you created earlier. Using the ``os.path.join()`` function, your code should look like the following example. .. code-block:: python TEMPLATE_PATH = os.path.join(PROJECT_PATH, 'templates') We again make use of ``os.path.join()`` to mash together the ``PROJECT_PATH`` variable and ``'templates'``, which would for example yield ``/tango_with_django_project/templates/``. We can then replace the hard-coded path we put in the ``TEMPLATE_DIRS`` tuple earlier with ``TEMPLATE_PATH``, just like in the example below. .. code-block:: python TEMPLATE_DIRS = ( # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. TEMPLATE_PATH, ) We can keep the ``TEMPLATE_PATH`` variable at the top of our ``settings.py`` module to make it easy to access should it ever need to be changed. This is why we created an additional variable to store the template path. .. _adding-a-template-label: Adding a Template ................. With your template directory and path set up, create a file called ``index.html`` and place it in the ``templates/rango/`` directory. Within this new file, add the following HTML code: .. code-block:: html Rango

Rango says...

hello world! {{ boldmessage }}
About
From this HTML code, it should be clear that a simple HTML page is going to be generated that greets a user with a *hello world* message. You might also notice some non-HTML in the form of ``{{ boldmessage }}``. This is a *Django template variable*, and we will be able to set a value for this variable to be displayed within the rendered output. We'll get to that in a moment. To use this template, we need to re-configure the ``index()`` view that we created earlier. Instead of dispatching a simple message, we will change it to dispatch our template. In ``rango/views.py``, add the following import statements at the top of the file. .. code-block:: python from django.template import RequestContext from django.shortcuts import render_to_response You can then update the ``index()`` view function as follows. Check out the inline commentary to see what each line does. .. code-block:: python def index(request): # Request the context of the request. # The context contains information such as the client's machine details, for example. context = RequestContext(request) # Construct a dictionary to pass to the template engine as its context. # Note the key boldmessage is the same as {{ boldmessage }} in the template! context_dict = {'boldmessage': "I am bold font from the context"} # Return a rendered response to send to the client. # We make use of the shortcut function to make our lives easier. # Note that the first parameter is the template we wish to use. return render_to_response('rango/index.html', context_dict, context) In our updated view, we use the ``RequestContext`` class to gain access to settings related to the user's ``request``. We then create a dictionary to store any data we want to send through to the template, then finally call the ``render_to_response()`` helper function. We pass as parameters the template we wish to use, the dictionary with our template variables, and the context we obtained from the user's ``request``. The ``render_to_response()`` function will take this data and mash it together with the template to produce a complete HTML page. This is then returned and dispatched to the user's web browser. When a template file is loaded with the Django templating system, a *template context* is created. In simple terms, a template context is essentially a Python dictionary that maps template variable names with Python variables. In the template we created earlier, we included a template variable name called ``boldmessage``. In our ``index(request)`` view example, the string ``I am bold font from the context`` is mapped to template variable ``boldmessage``. The string ``I am bold font from the context`` therefore replaces any instance of ``{{ boldmessage }}`` within the template. Now that you have updated the view to employ the use of your template, run the Django development server and visit http://127.0.0.1:8000/rango/. You should see your template rendered in all its glory, just like the example shown in Figure :num:`fig-rango-hello-world-template`. If you don't, read the error message presented to see what the problem is, and then double check all the changes that you have made. Ensure that all the changes required have been made. One of the most common issues people have with templates is that the path is set incorrectly in ``settings.py``. Sometimes it's worth adding a ``print`` statement to ``settings.py`` to report the ``PROJECT_PATH`` and ``TEMPLATE_PATH``. This example demonstrates how to use templates within your views. However, we have only touched upon some of the functionality provided by Django regarding templates. We will use templates in more sophisticated ways as we progress through this tutorial. In the meantime, you can find out more about `templates from the official Django documentation `_. .. _fig-rango-hello-world-template: .. figure:: ../images/rango-hello-world-template.png :figclass: align-center A screenshot of Google Chrome rendering the template used with this tutorial. Serving Static Media -------------------- Admittedly, the *Rango* website is pretty plain as we have not included any styling or imagery. `Cascading Style Sheets (CSS) `_, `JavaScript `_ and images are essentially *static media* files which we can include in our webpages to add style and introduce dynamic behaviour. These files are served in a slightly different way from webpages. This is because they aren't generated on the fly like our HTML pages. This section shows you how to setup your Django project to serve static media to the client. We'll also modify our template to include some example static media. Configuring the Static Media Directory ...................................... To get static media up and running, you will need to set up a directory in which static media files are stored. In your project directory (e.g. ``/tango_with_django_project/``), create a new directory called ``static``. Now place an image within the ``static`` directory. As shown in Figure :num:`fig-rango-picture`, we chose a picture of the chameleon, `Rango `_ - a fitting mascot, if ever there was one. .. _fig-rango-picture: .. figure:: ../images/rango-picture.png :figclass: align-center Rango the chameleon within our static media directory. With our ``static`` directory created, we need to tell Django about it, just like we did with our ``templates`` directory earlier. In ``settings.py`` file, we need to update two variables: ``STATIC_URL`` and the ``STATICFILES_DIRS`` tuple. First, create a variable to store the path to the static directory (``STATIC_PATH``) as follows. .. code-block:: python STATIC_PATH = os.path.join(PROJECT_PATH,'static') STATIC_URL = '/static/' # You may find this is already defined as such. STATICFILES_DIRS = ( STATIC_PATH, ) You've typed in some code, but what does it represent? The first variable ``STATIC_URL`` defines the base URL with which your Django applications will find static media files when the server is running. For example, when running the Django development server with ``STATIC_URL`` set to ``/static/`` like in the code example above, static media will be available at ``http://127.0.0.1:8000/static/``. The `official documentation on serving up static media `_ warns that it is vitally important to make sure that those slashes are there. Not configuring this problem can lead to a world of pain. While ``STATIC_URL`` defines the URL to access media via the web server, ``STATICFILES_DIRS`` allows you to specify the location of the newly created ``static`` directory on your local disk. Just like the ``TEMPLATE_DIRS`` tuple, ``STATICFILES_DIRS`` requires an absolute path to the ``static`` directory. Here, we re-used the ``PROJECT_PATH`` defined in Section :ref:`model-setup-templates-label` to create the ``STATIC_PATH``. With those two settings updated, run your Django project's development server once more. If we want to view our image of Rango, visit the URL ``http://127.0.0.1:8000/static/rango.jpg``. If it doesn't appear, you will want to check to see if everything has been correctly spelt and that you saved your ``settings.py`` file, and restart the development server. If it does appear, try putting in additional file types into the ``static`` directory and request them via your browser. .. caution:: While using the Django development server to serve your static media files is fine for a development environment, it's highly unsuitable for a production - or *live* - environment. The `official Django documentation on Deployment `_ provides further information about deploying static files in a production environment. Static Media Files and Templates -------------------------------- Now that you have your Django project set up to handle static media, you can now access such media within your templates. To demonstrate how to include static media, open up ``index.html`` located in the ``/templates/rango/`` directory. Modify the HTML source code as follows. The two lines that we add are shown with a HTML comment next to them for easy identification. .. code-block:: html {% load static %} Rango

Rango says...

hello world! {{ boldmessage }}
About
Picture of Rango First, we need to inform Django's template system that we will be using static media with the ``{% load static %}`` tag. This allows us to call the ``static`` template tag as done in ``{% static "rango.jpg" %}``. As you can see, Django template tags are denoted by curly brackets ``{ }``. In this example, the ``static`` tag will combine the ``STATIC_URL`` with ``"rango.jpg"`` so that the rendered HTML looks like the following. .. code-block:: html Picture of Rango If for some reason the image cannot be loaded, it is always nice to specify an alternative text tagline. This is what the ``alt`` attribute provides - the text here is used in the event the image fails to load. With these minor changes in place, kick off the Django development server once more and visit ``http://127.0.0.1:8000/rango``. Hopefully, you will see web page something like the one shown in Figure :num:`fig-rango-site-with-pic`. .. _fig-rango-site-with-pic: .. figure:: ../images/rango-site-with-pic.png :figclass: align-center Our first Rango template, complete with a picture of Rango the chameleon. The ``{% static %}`` function call should be used whenever you wish to reference static media within a template. The code example below demonstrates how you could include JavaScript, CSS and images into your templates - all with the correct HTML markup. .. code-block:: html {% load static %} Rango

Including Static Media

Picture of Rango Static files you reference will obviously need to be present within your ``static`` directory. If the file is not there or you have referenced it incorrectly, the console output provide by Django's lightweight development server will flag up any errors. Try referencing a non-existent file and see what happens. For further information about including static media you can read through the official `Django documentation on working with static files in templates `_. .. caution:: Care should be taken in your templates to ensure that any `document type declaration `_ (e.g. ````) you use in your webpages appears in the rendered output on the *first line*. This is why we put the Django template command ``{% load static %}`` on a line underneath the document type declaration, rather than at the very top. It is a requirement of HTML/XHTML variations that the document type declaration be declared on the very first line. Django commands placed before will obviously be removed in the final rendered output, but they may leave behind residual whitespace which means your output `will fail validation `_ on `the W3C markup validation service `_. The Static Media Server ----------------------- Now that you can dispatch static files, let's look at uploading media. Many websites provide their users with the ability to do this - for example, to upload a profile image. This section shows you how to add a simple development media server to your Django project. The development media server can be used in conjunction with file uploading forms which we will touch upon in Chapter :ref:`login-label`. So, how do we go about setting up a development media server? The first step is to create another new directory called ``media`` within our Django project's root (e.g. ``/tango_with_django_project/``). The new ``media`` directory should now be sitting alongside your ``templates`` and ``static`` directories. After you create the directory, you must then modify your Django project's ``urls.py`` file, located in the project configuration directory (e.g. ``/tango_with_django_project/tango_with_django_project/``). Add the following code to the ``urls.py`` file. .. code-block:: python # At the top of your urls.py file, add the following line: from django.conf import settings # UNDERNEATH your urlpatterns definition, add the following two lines: if settings.DEBUG: urlpatterns += patterns( 'django.views.static', (r'media/(?P.*)', 'serve', {'document_root': settings.MEDIA_ROOT}), ) The ``settings`` module from ``django.conf`` allows us access to the variables defined within our project's ``settings.py`` file. The conditional statement then checks if the Django project is being run in `DEBUG `_ mode. If the project's ``DEBUG`` setting is set to ``True``, then an additional URL matching pattern is appended to the ``urlpatterns`` tuple. The pattern states that for any file requested with a URL starting with ``media/``, the request will be passed to the ``django.views.static`` view. This view handles the dispatching of uploaded media files for you. With your ``urls.py`` file updated, we now need to modify our project's ``settings.py`` file. We now need to set the values of two variables. In your file, find ``MEDIA_URL`` and ``MEDIA_ROOT``, setting them to the values as shown below. .. code-block:: python MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(PROJECT_PATH, 'media') # Absolute path to the media directory The first variable ``MEDIA_URL`` defines the base URL from which all media files will be accessible on your development server. Setting the ``MEDIA_URL`` for example to ``/media/`` will mean that user uploaded files will be available from the URL ``http://127.0.0.1:8000/media/``. ``MEDIA_ROOT`` is used to tell Django where uploaded files should be stored on your local disk. In the example above, we set this variable to the result of joining our ``PROJECT_PATH`` variable defined in Section :ref:`model-setup-templates-label` with ``/media/``. This gives an absolute path of ``/tango_with_django_project/media/``. .. caution:: As previously mentioned, the development media server supplied with Django is very useful for debugging purposes. However, it should **not** be used in a production environment. The official `Django documentation on static files `_ warns that such an approach is *"grossly inefficient and insecure"*. If you do come to deploying your Django project, read the documentation to see an alternative solution for file uploading that can handle a high volume of requests in a much more secure manner. You can test this setup works by placing an image file in your newly created ``media`` directory. Drop the file in, start the Django development server, and request the image in your browser. For example, if you added the file ``rango.jpg`` to ``media``, the URL you should enter would look like ``http://127.0.0.1:8000/media/rango.jpg``. The image should show in your browser. If it doesn't, you'll need to go back and check your setup. Basic Workflow -------------- With the chapter complete, you should now know how to setup and create templates, use templates within your views, setup and use Django to send static media files, include images within your templates *and* setup Django's static media server to allow for file uploads. We've actually covered quite a lot! Creating a template and integrating it within a Django view is a key concept for you to understand. It takes several steps, but becomes second nature to you after a few attempts. #. First, create the template you wish to use and save it within the ``templates`` directory you specified in your project's ``settings.py`` file. You may wish to use Django template variables (e.g. ``{{ variable_name }}``) within your template. You'll be able to replace these with whatever you like within the corresponding view. #. Find or create a new view within an application's ``views.py`` file. #. Add your view-specific logic (if you have any) to the view. For example, this may involve extracting data from a database. #. Within the view, construct a dictionary object which you can pass to the template engine as part of the template's *context*. #. Make use of the ``RequestContext()`` class and ``render_to_response()`` helper function to generate the rendered response. Ensure you reference the correct template file for the first ``render_to_response()`` parameter! #. If you haven't already done so, map the view to a URL by modifying your project's ``urls.py`` file - and the application-specific ``urls.py`` file if you have one. The steps involved for getting a static media file onto one of your pages is another important process you should be familiar with. Check out the steps below on how to do this. #. Take the static media file you wish to use and place it within your project's ``static`` directory. This is the directory you specify in your project's ``STATICFILES_DIRS`` tuple within ``settings.py``. #. Add a reference to the static media file to a template. For example, an image would be inserted into an HTML page through the use of the ```` tag. Remember to use the ``{% load static %}`` and ``{% static "filename" %}`` commands within the template to make your life easier! #. Load the view that utilises the template you modified in your browser. Your static media should appear. The next chapter will look at databases. We'll see how to make use of Django's excellent database layer to make your life easier and SQL free! Exercises --------- Give the following exercises a go to reinforce what you've learnt from this chapter. * Convert the about page to use a template too from a template called ``about.html``. * Within the ``about.html`` template, add a picture stored within your project's static media.