Django Primer

Django is an awesome platform to develop. The documentation at djangoproject.com is fantastic but I feel the need for a basic tutorial that explains concepts instead of blindly walking the user through a some steps. I'm attempting to write one and here's the rough draft. It probably has tons of errors but I'm looking for feedback on the approach I've taken.

Note: All code used in the book is python but rarely valid/ working code. This is done for the purpose of simplicity while learning. For equivalent workingcode examples, please refer to included files.

MVC. It's all about making your mind seperate out the model, the view and the controller. Django is database-powered. How do we use the add, edit and remove information from the database? Surely, nobody likes writing SQL ‘select` and`insert` statements by hand. That’s the job of Django's Object RelationalMapper (ORM): It creates objects (or more specifically python objects) to control the database. A python class represents a table. Insatinating it givesus an object with which we can modify specific entries in the table. For example, consider table ‘foo` with fields `foo1` and `foo2`. A class `Bar` may now be created with members `bar1` and `bar2` which refer to `foo1` and `foo2`.Let’s instantiate `Bar` to derive a `bar` object.

INSERT INTO `foo`(`foo1`, `foo2`) VALUES (1,2) is equivalent to saying bar.bar1 = 1, bar.bar2 = 2, foo.save()
    SELECT * FROM `foo` WHERE `foo1` = 1 is equivalent to saying Bar.filter(bar1 = 1)

`Bar` is then called a _Model_ since it Models a table … ofcourse, like anyother class `Bar` can have nice member functions.

Every Model models a particular table, its members correspond to the fields in the table

Oh, I haven't told you the first thing about Django- Django is not magic.Django is just a collection of python classes and methods written in python.Django doesn't, in any way, restrict you from writing whatever python you want.It just has some nice directives you should follow to make life easier.

'nuff said. Let's move onto discussing a real-world application. Let's say a classic registration form. What are the elements that make it up (again, thinkin terms of MVC)? Each user is one table entry. So we need a model. Let's write one!

class User:
    """Models a typical user"""
    username = CharField(max_length = 20)
    # obviously, every database needs to know how large the string it's storing will be
    password = CharField(max_length = 20)
    country = CharField(max_length = 2)

And that's it! We're done. Now don't jump to ask why the password is a CharField and not some sort of password field. Remember what a model represents- it's a controller to the database. How can a database have a password field? Ofcourse, the password is stored in the database. It's just that it's shown as tiny asterisks (or more like some round dots in these modern systems) to the user.

Wait, is the password really stored in the database? Do you want gmail or yahoo database administrators to know your password and mess with your email?You'll hardly have an option to ‘recover` a password, just create a new one with the `forgot password` option in most places. What’s stored in the database then?A hash. A hash is like an encrypted version of your password that can never be decrypted again. Huh? How do they check my password when I enter it again in my login form? Simple, they hash the password your enter and compare it with the hash in the database. Okay, so where's the provision for hashing the password in this example? Idiot! What does the model have to do with hashing passwords?

What about country then? You want the user to fill in a two-letter country code instead of giving him a select box? Ofcourse not dummy, but again, how will a select-box be stored in the database? The value selected in the select box shown to the user will be stored in the database. Read more about Models here[^]

Okay, that was the model. Now how does Django know what the form to the user should look like? Ofcourse, you can write a big HTML form by hand in a nice old fashioned way. Try it. This is called a _Template_. A template is like a HTML page with some small methods and variables in it. Not python variables or methods- the template has its own language. The other option is to create a form using Django's newforms library. It again gives you nice objects representing the various widgets in a form and allows you to set their attributes. Okay, so let's write a form using newforms!

class RegistrtionForm:
    """Models a registration form"""
    username_field = CharField(label = 'Username', required = True)
    passwordhash_field = CharField(label = 'Password', widget = forms.PasswordInput(render_value = False), required = True)
    # notice how the widget parameter is passed to fine tune the actual widget used in the template
    # render_value is the property used to determine whether the password will appear as plain text or asterisks
    country_field = SelectField()

Nice! We have a form now. Obviously, since this is python code, it doesn't fit into the template so let's put it in a file called forms.py and use it in the template later. Read more about the newforms library here [^]

Just think about the template now… What do you want to show the user? Just aplain html form? Don't you want other bells-and-whistles, say a big heading screaming ‘Registration Form` and some styles to make your background pink? :POfcourse, you can have all that and whatever more you can do in HTML in your template. Before you start writing fancy css and javascript files, you should know one thing: Everything we’ve done so far actually fits into django as‘django files`.. models.py and forms.py and this registrationform.html but things like css files, js files, images, videos and other media don’t. They have to be linked externally. What do I mean to say? Yes, you have to have a separate source like foo.com/media hosting it. What? You don't have a webserver hosting all these things? Don't worry, Django can host it temporarily until you get one. All this content is labelled `static content` and should typically behosted by a completely different web server from Django.

Great! You have a form, a template and a model. One question: is Django telepathic? How on earth is it to know that username_field corresponds tousername or passwordhash_field corresponds to password? Regretting splitting the model and view yet? Don't fret, you'll see why it's useful to split it inmore advanced examples. Now we need something to link things up and performsome data processing like hashing the password field. This is the controller orironically named a `django view`. Hencefourth, I shall use view only in the context of models, views and templates. No more MVC fundamentals :P

A view. That's what we need to write. Incidentally, we forgot a minor detail…where will you access all this from in your web browser? In other words, what happened to urls? Django is built in with a fantastic url mapping engine (with regex support and other drooly stuff) which fundamentally maps a url to a view.So this view seems to be _such_ an important apect! It is directly called from the url map, links together models and templates _and_ does additional data processing… whew! Guess authors always reserve the hardest parts for the end uh?

Before actually writing a view, we need to understand a couple of things.Request and Response. Think of this whole Django website you're building as something generating a response to a certain request from the web browser. Whatis the form of this request and how should Django respond to it? You might have already heard about GET and POST, two very common methods of request'ing theweb server. Things like form data are POST'ed from the web browser to theserver. How does the server respond? It shows a "Thank you for registering"page. The point I'm trying to get at is that it doesn't suddenly throw up ormake coffee in response to some request (well, on second thought, it might actually throw up if you're still on Windows :P). It always responds with apage. Read more about request and response objects here [^].

Requests and corresponding responses also, very conveniently, become python objects in Django. A view is a method that accepts a request object (some GET/POST data) as an argument and responds with a response object (a page). Let's write a view!

from forms import *
from models import *
def register(request):
    """The register view"""
    if request.method == 'POST':
        # Ask your HTML form to POST
        form_data = RegistrationForm(request.POST)
        # How convenient! request.POST just fits into RegistrationForm so nicely
        if form_data.is_valid():
            # Did I forget to mention? Views also does form validation :P
            form_data.save()
            return render_to_response('success.html')
    render_to_response('registrationform.html', {'form': RegistrationForm()})
    # to render_to_response(), we're also passing a dictionary of "variables" to fill out in the template

That was complex enough, whew! Don't rejoice yet 'cos we're not done here!

  • request is a HttpRequest object, render_to_response returns a HttpResponse object
  • Notice how I conveniently left out the else statement. What should Django do if the form is invalid? Render the same form again? Yes, but surprise! It renders it with errors in place now :)
  • render_to_response() returns a HttpResponse. This essentially consists of a template (a html file) rendered with a "Context". Context is a dictionary of variables that need to be filled into the template. Read more about templates here [^].
  • Notice how I very conveniently wrote form_data.save(): What does it mean? What does it save to what? It obviously can't write the database because it isn't linked to the model yet. Well, it's an undefined method. Let's define it then!
class RegistrationForm:
    [...] <snip>
    from models import *
    def save(self):
        userInfo = User(username = self.cleaned_data['username_field'], password = hash(self.cleaned_data['passwordhash_field']), country =
        self.cleaned_data['country_field'])
        # ofcourse, the hash() function has to be defined somewhere
        # self.cleaned_data is a readymade dictionary which gives nice clean data ready for injecting into the database without further thought
        userInfo.save()

That was quick :) But what if we have 30 fields in place of three? This process becomes awesomely tedious. Shouldn't there be a more elegant way to link templates to models? After all, the data that we get do represent data to be written to the database using the Model. Ofcourse, there's a way. It's called ModelForms. Read more about using them here [^].

Okay, so everything's done and our registration form seems to be somewhat coherent. Let's point a url to it now. Django has a special name for this also: It's called _URLConf_. So let's look into the URLConf:

from django.conf.urls.defaults import *
urlpatterns = patterns('',
    (r'^$', 'myapp.views.register'),
)

Simple. Map ^$ to myapp.views.register method.

Unless otherwise stated, the content of this page is licensed under GNU Free Documentation License.