Develop your first web application in Django 1.10 – Part 1

In part 0 I discussed initial installation and configuration. Now it’s time to get into the code. The things I am going to do in this post are:

  • Understanding the concept of Project and Apps in Django world.
  • Creation of App.
  • Using templates to create home page.

Projects vs Apps

Django offers a very useful modular approach of creating web applications. Unlike other frameworks like PHP Laravel or Rails, Django let you create multiple apps under a project. This idea might look alien to those coming from the background of other frameworks where a project == app and you need to rely on routes etc to divide functionality. Let me take example of my own website.

                     

 

If you look at it, it contains a few static pages like Profile, Services, Testimonials etc and a couple of dynamic sections: Blog and Projects. If you are working on Rails or Laravel, you might come up with a group route to group relevant routes. This might work for task but what if you want to add a blog in another project, now you have no choice other than copy pasting code and manage accordingly, pretty boring right? Django will provide you following solution:

Django Architecture

 

I can now plug in as many apps as I want under a single Project (e.g: My Home Page) and Django will itself take care of the respective URLs of the app under a project. It is not necessary that you can only add your own app, you can incorporate any 3rd party app within your project and use it on your own.

App Creation

It’s time to create the app. I will name this app as tracker. Go to your newly created project folder, in my case ohbugztracker and run the following command:

./manage.py startapp tracker

Once it’s run it will create a new folder tracker and now your project directory will look like this:

Django project structure

 

You can things like migrations, admin.py, models.py and views.py.

The app is created but Django is still not aware of it, you will need to perform a couple of actions now. First, go to settings.py file and under INSTALLED_APPS section add your app entry for installation purpose.  It will then look like this:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'tracker',
]

And creation of urls.py file under tracker app folder.

from django.conf.urls import url
from . import views

urlpatterns = [
    url('^$', views.index, name='index')
]

Don’t get scared as I will be explaining what does it all mean.

OK so I installed my newly created app by adding into INSTALLED_APPS list and created urls.py. Let’s run the server and see how it goes. I run the server by running ./manage.py runserver and now visit: http://127.0.0.1:8000/tracker


Ouch! what’s that! Why am I seeing this! Wait! I forgot one thing. I did create urls.py under tracker folder but I did not add entry of it in main urls.py. No worries, there’s always a second chance. Go to main urls.py, in my case in ohbugztracker\urls.py

from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^tracker/$', include('tracker.urls')),
]

here I imported include first and then add the entry. It should work, right? Wrong! because now server is not starting and giving error:

url('^tracker/$', views.index, name='index')
AttributeError: module 'tracker.views' has no attribute 'index'

Fair enough as I have not added index method in views.py. Before I do it, let me exaplain what is happening.

As I mentioned in the diagram above, Django lets you add multiple apps under a project or I say under a domain(example.com). When you do something like:

url(r'^tracker/$', include('tracker.urls')),

You are telling server that when someone visits a URL http://127.0.0.1:8000/tracker, Django will try to match possible pattern, if found, it will include respective app.urls file. In our case it is tracker.urls.

If you notice, Django let you use RegEx to define your URLs pattern. Now let’s try again

Now open views.py file and add the following:

from django.shortcuts import render
from django.http import HttpResponse


def index(request):
    return HttpResponse('<h1>I am the root of Tracker App<h1>')

Here I imported HttpResponse and add a view method index which is responded a string in return. If you are a Laravel, Rails or any other MVC user, you might be surprised that why is it being called a View rather than a Controller. Here is a good explaination that Django is not an MVC framework but an MTV (Model Template View) framework. Now try again and you should see something like:

Cool! so we created and installed our new Django App and created a view method which displays text on visiting the application URL.

Before I move further, I will make a small change in my route file. Usually each app has it’s own unique url prefix, tracker in our case which helps to differentiate from other installed apps. Since there is only one app in our case, I will make a change in main urls.py file. Go to main urls.py and change the following from:

url(r'^tracker/$', include('tracker.urls')),

to

url(r'^$', include('tracker.urls')),

 

What actually I did, instead of making one to visit  http://127.0.0.1:8000/tracker to visit the only app, I just made it available on root URL. So now when I go to http://127.0.0.1:8000/ I will be seeing same page as you see above. Much better, right?

Tired, No? Good! Now just move to next step and integrate the markup of home page in our app.

Templates in Django

Like other web framework Django provides facility of Templates which not only helps to organize the presentation layer but also to avoid redundancy of the markup. I will discuss it further in next part, for the time being just bring our required HTML in the app.

First off, add the templates folder under your app folder tracker. Why templates folder? Well I just  set this in main settings.py under TEMPLATES DIRS key.

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

If you want, you may change it, I will go with the convention suggested by Django. Now go to templates folder and add another folder, named as layouts and add a file master.html in newly created layouts folder. In this file I am just dumping all the markup of HomePage of my application.

In next step add another html file under templates folder and call  it index.html and add the following line in it. Don’t worry I will explain it later in detail. Your folder structure should look like this:

{% extends "layouts/master.html" %}

Go to views.py file and make following changes:

from django.shortcuts import render

def index(request):
    return render(request, 'index.html')

Now I am using render method which accept request as first parameter and template file as a second parameter. If all goes well, you should be able to see the following:

 

In case you wonder why this all looking quite stylish, the reason is I am calling bootstrap from the CDN and since my own css files are not included it is just showing everything out of proportion at the moment. Later I will be calling all css/js files from local machine. I will be covering it in next post.

The Github repo has been updated for this project

 

If you like this post then you should subscribe to my blog for future updates.

* indicates required



4 Comments

  • Emmanuel

    Hi Andan!

    How often do you release the parts of this tutorial?

    Thanks in advance and my best wishes,
    Manu!

    • Adnan

      Good question 🙂

      I was supposed to end this series up by end of this month but got busy in some personal work. Will try to wrap it up ASAP!

      Subscribe to my newsletter to get latest updates