Learn Django – Chapter 3: Views, Templates and URLs 2


In Chapter 2, you have learned about the Django model and the admin site. They provide the very basic functions that are the same for almost all projects. Today, we will talk about Django Views, Templates and URLs. They will make you able to customize your project like you need it and to add the business logic that makes your application special.

Templates and static Files

 

In state of the art software development – people use to talk about MVC (Model View Controller) or MVT (Model View Template) architectures. This basically means that you seperate your data from your business logic and from the User Interfaces. This has a lot of advantages especially in terms of understanding, maintaining and extending your code – but we won’t go to much into detail here.

Django is an MVT framework (which is similar to MVC).

  • A request to a URL is dispatched to a View
  • The View prepares the data using the Model.
  • The data is “rendered” with a Template.

 

_images/day-3-django-flow.png

Django Flow

 

  • Model: Data Layer – interacts with the database. events/models.py is the Model in our example.
  • View: Presentation Layer – It prepares the data for the template.events/views.py is the View in our example.
  • Template: Defines how data will look like. Actual HTML layout.events/templates/events/home.html is a template in our example.

The framework itself acts as the controller – it sends a request to the appropriate view, according to the Django URL configuration.

 

Do you remember that we have added a custom home page in DAY-1?

In events/views.py, the following code was added:

def home(request):
     return render('home.html')

Here we defined a View.

And also another file was added events/template/events/home.html.

Here we defined a Template.

Now let us add more views and templates. Checkout the next code by:

git checkout -f day-3-step-1

Changes:

  1. In events/views.py, following chnages are made:

At the top we import our Event Model:

from .models import Event

And then we also add a view to list our Events:

1
2
3
def list(request):
   event_list = Event.objects.all();
   return render(request, 'events/list.html', {'event_list': event_list})
  1. Line 1: Function definition. Here we have defined a list function. In Django views, all functions have “request” as the first parameter.
  2. Line 2: Here we get a list of all Events from the database and save it into the “event_list” variable.
  3. Line 3: Finally we render the data that we prepared with the “events/list.html” template. We pass the data as variables to the template.
  1. A new Template file events/templates/events/list.html is added.

    1
    2
    3
    4
    5
    6
    <h1>Events</h1>
    <ul>
    {% for event in event_list %}
      <li>{{event.title}}</li>
    {% endfor %}
    <ul>
    
    1. Line 3: The event_list variable is passed from the view. In the Template we create a “for loop” to show all events.
    2. Line 4: Here we are accessing the title of event object.
    3. Line 5: End for loop.
  2. In myevent/url.py, the following line is added

    url(r'^events/$', 'events.views.list', name='event_list'),
    

    This maps the URL /events/ to the List View that we just created. We get more into details later.

  3. Finally we have also added a BROWSE link on our custom home page inevents/templates/events/home.html

    <a class="lstye home" href="/events">Browse</a>
    

Now run the project, reload the home page and click on the “Browse” link.

 

_images/frontend-event-list.png

Custom Event List

 

Static Files

 

Cool – we created a custom Event view with our own template. But wait, it looks so ugly. Let’s add some style!

git checkout -f day-3-step-2

So please review the Changes:

  • In events/template/events/list.html, we have added lot of html code. Most important is:

    1. We are loading templatetags:
    {% load staticfiles %}
    
    1. We added more CSS files to add styles in our page:
    <link href="{% static "css/bootstrap.css" %}" rel="stylesheet" media="screen">
    <link href="{% static "css/style.css" %}" rel="stylesheet" media="screen">
    <link href="{% static "css/font-awesome.css" %}" rel="stylesheet" media="screen">
    <link href="{% static "css/responsive.css" %}" rel="stylesheet" media="screen">
    
  • New files added:

    1. CSS files have been added in template/static/css/font-awesome.css
    2. CSS files have been added in template/static/css/responsive.css
    3. Fonts have been added in template/static/css/fonts directory
  • We have also made some changes in forloop part in list.html:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    {% for event in event_list %}
      <li {% if forloop.counter|divisibleby:2 %} class="timeline-inverted"{% endif %}>
          <div class="timeline-badge">
            <a><i class="fa fa-circle" id=""></i></a>
          </div>
          <div class="timeline-panel">
              <div class="timeline-heading">
                  <h4><a href="{% url 'event_detail' event.id %}">{{event.title}}</a></h4>
              </div>
              <div class="timeline-body">
                  <p class="timeline-desc col-md-6">{{event.description | truncatewords:20}}</p>
                  <p class="timeline-other col-md-6">
    
                    <em class="timeline-item">
                     Venue : {{event.venue}}
                    </em>
                    <em class="timeline-item">
                    Ticket: {{event.amount}}
                    </em>
                    <em class="timeline-item">
                    Date : {{event.date}}
                    </em>
                  </p>
              </div>
          </div>
      </li>
      {% endfor %}
    

    Line 11: There is templatetags truncatewords. This will show only 20 words description.

Reload your browser page. Now – that’s much better!

_images/frontend-event-list-style.png

Figure 3.3: Event list with style added.

Looks better? Compare Figure 3.3 and Figure 3.2.

Note

By the way. You don’t have to develop templates yourself – you can download free awesome templates for your Django development and just integrate them. Ours was taken fromhttp://themewagon.com/demo/evento-free-responsive-one-page-event-template

Event Detail Page

 

So far we made a page that shows a list of all events. Next – we are going to setup an event detail page where we can see all information about a specific event.

What we need to do is:

  • create a new view (detail)
  • create a new template (detail.html)
  • map a URL pattern to the view
  • modify Event list, so that titles are not just text – but links
git checkout -f day-3-step-3

Please review all the Changes:

  • In events/views.py, detail() function is added.

    def detail(request, id):
       event = Event.objects.get(id=id)
       return render(request, 'events/detail.html', {'event': event})
    

    Note

    Please note that this view has an additional “id” parameter. It will be passed from the user as a parameter.

  • File events/template/events/detail.html is added.

  • In myevent/url.py, following lines are added:

    url(r'^events/(?P<id>\d+)/$', 'events.views.detail', name='event_detail')
    

    Note

    The cryptic “(?P<id>d+)/$” extracts a number from the URL (e.g. /events/10) and passes the number to the view as a parameter with the name “id”.

  • In events/tempalte/evetns/list.html, title gets a link:

    <h4><a href="{% url 'event_detail' event.id %}">{{event.title}}</a></h4>
    

    Note

    The {% url 'event_detail' event.id %} will lookup the URL pattern with the name ‘event_detail’ from the URL config file. And it will add a parameter “event.id” to it. The linke will be displayed with the events title.

Now reload your browser with the event list and click on the title of any event. It will take you the event detail page.

 

 

More on templates

 

If take a close look on events/template/events/list.html andevents/template/events/detail.html, you will notice that both files repeat the same code in their header and footer. Django highly encourages you to use DRY ( Don’t Repeat Yourself) templates. This means that you should not repeat your code across different locations – specifiy it once and include it everywhere you need it. This makes it much easier in the future to maintain and extend your code. So let’s apply this principle to our code …

git checkout -f day-3-step-4

Changes:

  • We have added a new file template/html/base.html. All common html code (mainly header and footer part) fromevents/template/events/list.html andevents/template/events/detial.html is moved here. We also introduce this block here:

    {% block 'content' %}
    {% endblock %}
    
    This is a placeholder for specific content that will be displayed in our basic page layout. 'content' is just a variable name.
    
  • In events/template/events/list.html andevents/template/events/detial.html, we have added:

    {% extends 'base.html' %}
    

    This tells Django that this template extends the base.html template. It takes everything from base.html and makes it more specific where variables can be applied.

  • We have also modified a line in myevent/settings.py. Look in TEMPLATEpart

    ....
    os.path.join(BASE_DIR, 'template', 'html')
    ....
    

    This is to indicate where our base.html file is saved.

Reload your browser. You should not see any difference – but your code is much cleaner now!

 

 

URL configuration

 

Let’s take a closer look at the URL configuration file. Why do we always have to configure the url.py file – that seems annoying … but for a professional development cycle it makes perfect sense. URLConf helps you to map requested URLs to functions in views. It acts as router. It makes your code very flexible to add, move or remove functions. As it is a white list – it gives you a simple and complete overview what functions your application is offering to the user, which also enhances the security of your application development (functions without URL config cannot be called).

In our example, till now we have four URLs patterns configured:

url(r'^admin/', include(admin.site.urls)),
url(r'^$', 'events.views.home', name='home'),
url(r'^events/$', 'events.views.list', name='event_list'),
url(r'^events/(?P<id>\d+)/$', 'events.views.detail', name='event_detail'),
  • Any request that starts with /admin, will match first line. Requests like/admin or /admin/events or /admin/whatever are matched. This is because we don’t have a “$” sign at end. The $ sign is a special “regex” character to indicate the END of a string.
  • A request / will match second line and call theevents.views.home(request) function.
  • Similarly, requests to /events/ match the third URL pattern. They will get routed to the list function.
  • In the fourth pattern, we configure to “catch” a value from the URL and pass it to a fucntion. A request like /evens/1 will callevents.views.detail(request, 1). The ‘d+’ means that the parameter may only be a number (digit) – not a string.

 

Dynamic Home

 

So let’s come back to our custom home page from DAY 1. It is still static – and not showing content from our database. We are going to change this now.

git checkout -f day-3-step-5

Please review the following Changes:

  • changes in events/views.py

import datetime function from core Python, at very top.

from  datetime import datetime

The home() function:

1
2
3
4
5
6
def home(request):
    try:
        event = Event.objects.filter(date__gt=datetime.now()).order_by('date')[:1][0]
    except:
        event = []
    return render(request, 'events/home.html', {'event': event})
  1. Line 3: 1. We have fetched all events that will be happening in the future, Event.objects.filter(date__gt=datetime.now()) 2. We limit the results to only 1 event, that we want to promote on our home page (take the first in order of date) [:1][0]
  2. The command in Line 3 can fail (e.g. when no new Events are in the database). In this case Python will throw an Exception which we catch. In that case we set “Event” to be an empty list.
  3. In the last step, we render the page with the “home.html” template and pass “event” as a parameter to the template.
  • Changes in events/template/events/home.html:
Now we make the values of the home page dynamic. They are taken from the event object passed by the view. Notice all values between {{ }}, are changed.

Reload your browser and check the home page.

 

Excercises

 

  1. Sort your Events List by Date

  2. Filter your Event list so that only future events are visible. (Make sure you have added at least one event that has a future date in your admin site)

  3. An Event Site needs Social Media. Add a social sharing widget to your templates. Create a “Learn Django on slash4.de” Event and try sharing it on Twitter / Facebook etc.

    Here is the code that you need for your sharing widget. Integrate it into your detail template:

    <script type="text/javascript" src="//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-55ae89800d295a5e" async="async"></script>
    
    <div class="addthis_native_toolbox"></div>
    

We can download solutions for assignment 1 and 3.

git checkout -f day-3-solution-1

Checkout list() function in events/views.py.

 

 

 

Ok, that’s it for today! Please come back tomorrow and check out Chapter 4, about Authentication and Forms.

If you like this tutorial – please share it with your friends or leave a comment below.


Leave a comment

Your email address will not be published. Required fields are marked *

2 thoughts on “Learn Django – Chapter 3: Views, Templates and URLs

  • Arun Dev

    by far the best get started with Django tutorial available on the Internet .. the best thing is its free.. He makes total sense.. I watched paid videos on some sites and was unclear but just using his tutorial I have setup and started running web apps … Thanks a lot…. PS am not even a web developer .. I am an embedded linux developer.. yet it was easy to understand with his tutorial….