Thursday, January 5, 2017

Django - 007 - Our first URLconf

If, at this point, you ran python manage.py runserver again, you would see the Welcome to Django message, with no trace of our Hello World view anywhere. That is because our myD3site project does not know about the hello view; we need to tell Django explicitly that we are activating this view at a particular URL. Continuing our previous analogy of publishing static HTML files, at this point we have created the HTML file but have not uploaded it to a directory on the server yet.

To hook a view function to a particular URL with Django, we use a URLconf. A URLconf is like a table of contents for your Django-powered website. Basically, it is a mapping between URL's and the view functions that should be called for those URL's. It is how you tell Django, For this URL, call this code, and for that URL, call that code.

For example, when somebody visits the URL /foo/ , call the view function foo_view() , which lives in the Python module views.py. When you executed django-admin startproject, the script created a URLconf for you automatically: the file urls.py

By default it looks something like this:

"""myD3site URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.10/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin

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

If we ignore the documentation comments at the top of the file, here is the esssence of a URLconf:

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

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

Let us step through this code one line at a time:


  1. The first line imports two functions from the django.conf.urls module: include which allows you to include a full Python import path to another URLconf module, and url which uses a regular expression to pattern match the URL in your browser to a module in your Django project. 
  2. The second line calls the function admin from the django.contrib module. This function is called by the include function to load the URLs for the Django admin site. 
  3. The third line is urlpatterns - a simple list of url() instances. 

The main thing to note here is the variable urlpatterns, which Django expects to find in our URLconf module. This variable defines the mapping between URL's and the code that handles those URLs. To add a URL and view the URLconf, just add a mapping between a URL pattern and the view function. Here is how to hook in our hello view:

from django.conf.urls import include, url
from django.contrib import admin
from myD3site.views import hello

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

We made two changes here:
First, we imported the hello view from its module - myD3site/views.py , which translates into myD3site.views in Python import syntax. (This assumes myD3site/views.py is on your Python path.)
Next, we added the line url(r'^hello/$',hello), to urlpatterns. This line is referred to as a URLpattern. The url() function tells Django how to handle the URL that you are configuring. The first argument is a pattern matching string(a regular expression, more on this in a bit) and the second argument is the view function to use for that pattern. url() can take other optional argument as well, which we will cover in more depth later.

One more important detail we have introduced here is that r character in front of the regular expression string. This tells Python that the string is raw string - its contents should not interpret backslashes.

In normal Python strings, backslashes are used for escaping special characters - such as in the string \n, which is one character string containing newline. When you add the r to make it a raw string, Python does not apply its backslash escaping - so, r'\n' is a two character string containing a literal backslash and a lowercase n.

There is a natural collision between Python's usage of backslashes and the backslashes that are found in regular expressions, so it is best practice to use raw strings any time you are defining a regular expression in Django.

In a nutshell, we just told Django that any request to the URL /hello/ should be handled by the hello view function.

It is worth discussing the syntax of this URL pattern, as it may not be immediately obvious. Although we want to match the URL /hello/ , the pattern looks a bit different than that.

Here is why:


  • Django removes the slash from the front of every incoming URL before it checks the URLpatterns. This means that our URLpattern does not include the leading slash in /hello/. At first, this may seem unintuitive, but this requirement simplifies things - such as the inclusion of URLconfs within other URLconfs, which we will cover later. 
  • This pattern includes a caret (^) and a dollar sign ($). These are regular expression characters that have a special meaning: the caret means require that the pattern matches the start of the string , and dollar means require that the pattern matches the end of the string


This concept is best explained by example. If we had instead used the pattern ^hello/ (without a dollar sign at the end), then any URL starting with /hello/ would match, such as /hello/foo and /hello/bar , not just /hello/.

Similarly, if we had left off the initial caret character (that is, hello/$), Django would match any URL that ends with hello/, such as /foo/bar/hello.

If we had simply used hello/, without a caret or dollar sign, then any URL containing hello/ would match, such as /foo/hello/bar.

Thus, we use both the caret and dollar sign to ensure that only the URL /hello/ matches - nothing more, nothing less. Most of your URLpatterns will start with carets and end with dollar signs, but it is nice to have the flexibility to perform more sophisticated matches.

You may be wondering what happens if someone requests the URL /hello (that is, without a trailing slash). Because our URLpattern requires a trailing slash , that URL would not match. However, by default any request to a URL that does not match a URL pattern and does not end with a slash will be redirected to the same URL with a trailing slash. (This is regulated by the APPEND_SLASH Django setting.)

The other thing to note about this URLconf is that we have passed the hello view function as an object without calling the function. This is a key feature of Python (and other dynamic languages): functions are first-class objects, which means that you can pass them around just like any other variables. Cool stuff, eh?

To test our changes to the URLConf, start the Django development server by running the command:

$ python manage.py runserver
Performing system checks...

System check identified no issues (0 silenced).
January 05, 2017 - 17:32:10
Django version 1.10.4, using settings 'myD3site.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

(If you left it running, that is fine too. The development server automatically detects changes to your Python code and reloads as necessary, so you do not have to restart the server between the changes.)

The server is running at the address : http://127.0.0.1:8000/

so open up a web browser and go to : http://127.0.0.1:8000/hello/

You should see the text Hello World - the output of your Django view.

This is our first Django view. Congrats.






No comments:

Post a Comment