LJ Archive

At the Forge

Django

Reuven M. Lerner

Issue #250, February 2015

Have you looked at Django lately? The leading Python Web framework has many new and interesting features for old and new users alike.

So, you want to write a Web application? Well, the good news is that you aren't lacking for languages or frameworks. Nearly every modern language supports a number of different frameworks, allowing you to choose from one that best matches your development needs and style. If you are a Python user, chances are you have heard of Django, a project launched in 2005 that often is compared with Ruby on Rails.

Django is not the only Python Web framework. Besides Flask, a microframework that I have written about here in the past, there are several other ways you can use Python to create a Web application. However, there's no doubt that Django is the best-known framework, as well as the most popular one, in the Python world. It is used to power large sites (such as Pinterest and Instagram) as well as numerous small and internal ones. Just as important, the Django community has demonstrated that it is both active and strong, moving development from a BDFL (benevolent dictator for life) model to the Django Software Foundation, a nonprofit entrusted with organizing, funding and promoting Django development.

Django often is compared with Ruby on Rails, and for good reason. Indeed, anyone who knows both Ruby and Python, and who knows Rails well, should be able to start getting work done in Django within less than a day. At the same time, I would say that Django adopts and promotes Python conventions and attitudes wholeheartedly. This contrasts with Rails, whose developers often have attitudes and conventions that go against what the Ruby language has promoted.

If you have a firm understanding of Python's modules and packages, much of Django will make perfect sense to you and will allow you to make use of that knowledge.

So in this article, I begin to cover Django and how you can use it in your Web projects. I plan to look at various parts of Django during the coming months, including many of the recent updates to this framework that make it particularly flexible and powerful, as well as a generally good choice for many organizations—especially those that already are using Python.

Starting with Django

Most people, when they want to develop a Web application, think of it as just that—an “application”. (Or, if I want to pretend to be cooler than I actually am, I could just call it a “Web app”.) In Django, however, you think in terms of a “project”. Each Django project, however, contains a number of applications, and each of them has its own Python code, as well as its own business logic and templates for displaying data.

This division of a Django project into separate applications took me some time to get used to. However, I think that it's a great way to operate and makes it possible to leverage existing code in new Django projects easily. It also forces me, as a developer, to break my code into small parts, which increases the chances that I'll be able to re-use that code in future projects.

To create a new Django project, you first must download and install this package from PyPi, the Python Package Index. The easiest way to do so is to use the pip command, which I'm delighted to say has been incorporated into the latest (2.7.9 and 3.4) versions of Python. Thus, you can type:

pip install django

and ensure that Django is installed. By default, Django will use SQLite3, which is installed on the computer by default, and for which libraries come along with Python. (Depending on your computer's configuration, you might need to execute the pip command as root, using sudo.) As I write this, the latest stable version of Django is 1.7.1, which includes a number of new and interesting features.

Once you have installed Django, you need to start a project. The installation of Django creates, among other things, a command on your computer called django-admin.py, which can be used to administer various parts of a Django project. For example, to create a new project, you can say:

django-admin.py startproject atfproject

Assuming that nothing named “atfproject” already exists in the current directory, this will create a new directory named atfproject, which will serve as your Django project. If you're using Git, you immediately should enter into this directory, initialize a new repository and then commit the files. This will ensure that even if you mess something up, you'll always be able to return to the initial, stable state that Django gave you out of the box.

If you enter the atfproject directory, you'll see that it contains two different things. First, it contains a manage.py program, which you will use (not surprisingly) to manage your Django project. Second, it contains a subdirectory with the same name as the project's main directory (atfproject), which contains the project's main configuration and code. I find it a bit confusing that there are two directories, one within the next, named the same thing, but I have gotten used to it over time.

The inner project directory is a Python package, complete with an __init__.py file, as well as three other files: settings.py, urls.py and views.py.

The first, settings.py, contains the overall settings for the Django project. This file defines, for example, whether you want to be in debugging mode (DEBUG = True), what database driver you want to use (DATABASES) and what applications should be added to your project (INSTALLED_APPS). You already can see, if you look at settings.py, that INSTALLED_APPS is a tuple of strings, in which each string describes a Python package containing a Django app.

The second file, views.py, contains the definitions of view functions. I'll get back to those in a moment, when I describe creating your first application and then writing some view functions within it.

The third file, urls.py, provides Django with a mapping between URLs and the view functions. It allows you to say that if a request comes in for the URL /abc, you'll want to execute function “abc” as a result. (You'll soon use this URL configuration.)

You might think, given the number of times I have written that “I'll discuss” a certain topic, that there's a great deal more configuration to do in order to run your Django project. But that's actually not the case. Even without any code, you already can start the Django application running on your computer. Inside the top-level project directory, invoke:

./manage.py runserver

As the name suggests, this starts a simple HTTP server and then connects your Django application to that server. By default, the server listens on port 8000. This means that by pointing your Web browser to http://localhost:8000, you will see the home page of your new Django project. Not surprisingly, it doesn't say or do much other than tell you that you have successfully installed and run a new project.

Creating an Application

Let's add an application to the Django project. This also will give you a chance to create a simple view function, as well as a URL path that allows people to invoke your function.

The first step in creating an application is to use the manage.py program in the top-level directory of your Django project. Simply invoke:

./manage.py startapp atfapp

And, you'll soon have a new Django application (atfapp) set up inside your project. What does a Django application contain? Well, if you look inside of the atfapp directory, you'll find a Python package. The directory contains an empty __init__.py file, but then contains four other files: admin.py, models.py, tests.py and views.py.

For now, let's concentrate on views.py, which is where you can define the “view functions” for your application. Django calls itself an MTV framework, in which MTV stands for model, template and view. This is slightly different from the MVC (model-view-controller) model of application design used by Rails and several other frameworks. In MVC, the controller receives the request, communicates with models that represent the business logic and then displays things using views.

In Django, things work a bit differently. The HTTP request is directed to a view function by the urls.py file in the Django project's package directory. Based on the URL object, a view function then is invoked. This view function then communicates with one or more models and then renders a template. If you're coming from an MVC framework like Rails, there's a clear overlap (but still a distinction) between MVC controllers and MTV view functions.

Let's look at how one of these might work. Open up views.py in the application's directory (that is, atfapp/views.py). Add the following to it:

from django.http import HttpResponse

def hello(request):
return HttpResponse("hello, world")

Let's start with the function. Every view function takes at least one parameter, traditionally called “request”. This request object represents the HTTP request that was submitted to the HTTP server. If and when you want to inspect or display elements of the request, you can do so, but for now let's ignore it.

In fact, let's ignore any potential inputs and just return a basic, simple HTTP response. You do this by returning not a string, but an HttpResponse object, which you create by passing the class a string (“hello, world”). Of course, you also need to make sure that HttpResponse is defined, so you use Python's “from - import” statement to bring in the name from the django.http package.

Once this function is defined in views.py, you're just about set to go. But before it can be invoked via the Web, you need to tell Django what URL will reach it. For this, you must return to the urls.py file in the project's package directory and tell Django that you want to have the root URL (that is, /) lead to your “hello” view function.

To do this, you first need to import your application's “views” module into urls.py. Once again, you can see how Django uses Python's standards in an intelligent way; if the application is called atfapp and the views file is views.py inside of that directory, you merely have to say:

from atfapp.views import hello

at the top of urls.py. Once that is done, the name “hello” is defined in the global namespace for urls.py, and you can reference your function by that short name.

You then have to tell Django to point to your function when it receives an HTTP request for /. You do this by creating a URL object and passing it two parameters: a string containing a regular expression and a function. Note that the regular expression can (and often should) contain the ^ and $ characters to anchor the URL to the start and finish of the URL. Moreover, the leading / character of a URL doesn't appear by default in these URL mappings. Thus, to point / to your “hello” function, you configure Django as follows:

url(r'^$', hello)

Sticking this into the call to the “patterns” function in urls.py that Django installed by default, you end up with the following definitions:

urlpatterns = patterns('',
    url(r'^$', hello),
    url(r'^admin/', include(admin.site.urls)),
)

Because Django is running in debug mode, you don't even need to restart your project. Django notices the change to urls.py and restarts the server. Point your browser to http://localhost:8000/, and sure enough, you'll see “hello world”.

Named Parameters

That's not bad for a tiny bit of code! But let's go one step further. Say you don't want the URL to be /, but want it to be /hello/NAME instead, where NAME can be someone's name. You then want the view function to notice that name and use it when displaying output.

This means you'll not only have to adjust your URL, but that the URL will need to have a variable second part (that is, NAME), which then will be passed to your view function.

Amazingly, Django makes this very simple, but only if you're comfortable with some of the more advanced features of regular expressions. If you have any experience with regexps, you probably know that you can group characters using parentheses. You probably also know that you can use a question mark (?) to indicate that the preceding character is optional. So in theory, it should be illegal for a regexp to contain a question mark just inside a pair of parentheses, as in:

(?foo)

Python, however, allows for this to happen and treats it specially. If, after the question mark, you put the letter P and then a name inside <angle brackets>, the group is captured within the regular expression. Better yet, the captured text can be referred to by name. So if you change your URL to be:


^hello/(?P<name>\w+)$

it will capture one or more alphanumeric characters (\w+) following “hello/” in the URL. These will be turned into the named group, “name”. In urls.py, this will look like the following:


url(r'^hello/(?P<name>\w+)$', hello),

Once you have done that, you can rewrite your “hello” function, such that it now takes a second parameter, named (not surprisingly) “name”. That's right; the named group in your regular expression is then passed to your function as a parameter. I love this feature and find it to be quite elegant—if you can get over the learning curve that people have for regular expressions.

Now change your view function, such that it takes a second parameter:

def hello(request, name):
    return HttpResponse("hello, {}".format(name))

And sure enough, after the server reloads, you can visit /hello/Reuven and get a personalized greeting.

Conclusion

In this article, I describe setting up a very simple Django project with an application and wrote a basic view function. In my next article, I'll look at Django's templates and show how you can pass data to them as well as modify that data from within the template without any code.

Reuven M. Lerner is a Web developer, consultant and trainer. He recently completed his PhD in Learning Sciences from Northwestern University. You can read his blog, Twitter feed and newsletter at lerner.co.il. Reuven lives with his wife and three children in Modi'in, Israel.

LJ Archive