Skip to content

Django

Doc site quickstart

This site has been superseded

This was an early attempt at django, probably very out of date

This is a quick guide to install this doc site from scratch, almost.. For a more detailed description you will have to read past this quickstart. Checkout the docs, which is a sub-directory of klopt.web(/doc) so this should do :

doc site
1
2
3
svn co https://klopt.googlecode.com/svn/klopt.web/doc
cd doc
./mysql.py 

You could save some time by disabling the drop_table and create_table functions in mysql.py , since once created, these are not needed anymore. Also alter credentials in mysql.py. Sub check, see if this runs :

install
su 
apt-get install python python-django python-pip python-docutils mysql-server
apt-get install python-pygments python-beautifulsoup python-markdown
python -c 'import django'

mkdir /var/www/django
cd /var/www/django
svn co https://klopt.googlecode.com/svn/django/klopt
cd klopt
python manage.py runserver

A small sub check again, see what this says:

web server
chromium-browser http://127.0.0.1:8000/

In theory ;) this should give you a working site under the development server, but of course we want it under apache, so make sure you have the module enabled :

apache install
apt-get install libapache2-mod-wsgi
a2enmod wsgi

And add to (or create) the file /etc/apache2/sites-available/django :

wsgi
1
2
3
4
5
6
7
WSGIScriptAlias /doc /var/www/django/klopt/klopt/wsgi.py
WSGIPythonPath /var/www/django/klopt



Order deny,allow
Allow from all

Enable and restart :

restart
a2ensite django
service apache2 restart

If you stumbled upon problems, you might find something in the next chapters.

Installation

This is the simple setup, just to get started, you might want it running under apache later on.. . Pending .... I installed it from aptitude, but you can also use pip :

install
apt-get install python python-django python-pip python-docutils

A test for a successful setup would be :

test
python -c 'import django'

Project Setup

Django comes with a great tool django-admin which you can use to setup a project. This will create a new projects directory for you :

django-admin
django-admin startproject klopt

You will have this directory structure after that command : With the aid of http://www.online-toolz.com/tools/unicode-html-entities-convertor.php"

directory structure
└── klopt
    ├── klopt
    │   ├── __init__.py
    │   ├── __init__.pyc
    │   ├── settings.py
    │   ├── settings.pyc
    │   ├── urls.py
    │   ├── urls.pyc
    │   ├── wsgi.py
    │   └── wsgi.pyc
    └── manage.py

You can now run the built-in django server like this :

run server
cd klopt
python manage.py runserver

It will tell you on which url this will be running :

startup message
1
2
3
4
5
6
Validating models...

0 errors found
Django version 1.4.5, using settings 'klopt.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

If you need to access this from another machine, you will have to overwrite by binding to the external address : So you can check that url to see if it works. If not.. sorry your on your own because everything works out of the box for me. I'm starting to like django ;)

different ip:port
python manage.py runserver 192.168.2.8:8000

Leave the server running in a window for some debugging output. Also to see that it even detects when you change a file (note it monitors existing files, so creation of a new one still needs as server restart!) For instance, edit the settings.py file to use mysql, and also create a django database and grant rights in mysql of course. Then look at the server output when you save the file.

Application Setup

Now for some apps in the new projects, you can run :

startapp
django-admin startapp testapp

Do not call the app the same as the projects, e.g. klopt and klopt. This will fail with an error resembling :

conflict
klopt conflicts with the name of an existing Python module and cannot be used as an app name. Please try another name.

This is because both the project and the app have their own sub-directory under the root, so they will interfere. So just invent another app name. This will augment the project structure like this.

directory
.
└── klopt
    ├── klopt
    │   ├── __init__.py
    │   ├── __init__.pyc
    │   ├── settings.py
    │   ├── settings.pyc
    │   ├── urls.py
    │   ├── urls.pyc
    │   ├── wsgi.py
    │   └── wsgi.pyc
    ├── manage.py
    └── testapp
        ├── __init__.py
        ├── __init__.pyc
        ├── models.py
        ├── models.pyc
        ├── tests.py
        └── views.py

Installing a database table

You don't do much SQL in django, but you create a model and django makes a table for it. Open the file models.py in your app directory and fill it with this:

models
from django.db import models
from django.core.urlresolvers import reverse

class Post(models.Model):
    title = models.CharField(max_length=255)
    slug = models.SlugField(unique=True, max_length=255)
    description = models.CharField(max_length=255)
    content = models.TextField()
    published = models.BooleanField(default=True)
    created = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['-created']

    def __unicode__(self):
        return u'%s' % self.title

    def get_absolute_url(self):
        return reverse('testapp.views.post', args=[self.slug])

Now make sure you have configured the database in mysql and in settings.py You need to create a database in according to the settings in project/settings.py :

database setup
1
2
3
4
5
6
DATABASES = {
'default': {
    'ENGINE': 'django.db.backends.mysql', 
    'NAME': 'django',
    'USER': 'django',  
    'PASSWORD': 'somepassword',     

The mysql command for this would be :

privileges
grant all privileges on django.* to django@localhost identified by 'somepassword';}

Then run.

syncdb
python manage.py syncdb

If no errors, you will now have a database table called 'testapp.post' with the columns matching the members of the python class. Also the first time 'syncing' some more django and authority tables will me created.

admin app

This is a neat app delivered with django, but disabled by default. To enable edit settings.oy again and find the INSTALLED_APPS tuple. Uncomment both

admin
1
2
3
4
# Uncomment the next line to enable the admin:
'django.contrib.admin',
# Uncomment the next line to enable admin documentation:
'django.contrib.admindocs',

Also uncomment the corresponding lines in url.py, since you will have to uncomment 4 lines, i might as well include the whole file as it should be :

url
from django.conf.urls import patterns, include, url

# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    # Examples:
    # url(r'^$', 'klopt.views.home', name='home'),
    # url(r'^klopt/', include('klopt.foo.urls')),

    # Uncomment the admin/doc line below to enable admin documentation:
    url(r'^admin/doc/', include('django.contrib.admindocs.urls')),

    # Uncomment the next line to enable the admin:
    url(r'^admin/', include(admin.site.urls)),
 )

Now browse to localhost:8000/admin and you will get a login. Fill in the name you entered during setup. You can now add users, groups and sites.

register testapp

The sample application is a blog site, register it by making a file call admin.py inside the testapp directory.

register
1
2
3
4
from django.contrib import admin
    from testapp.models import Post

    admin.site.register(Post)

This would be enough to register the site and make it appear on the admin console. But a little more tweaking is needed to get better descriptions, add some filters etc...

admin filters
from django.contrib import admin
from testapp.models import Post

class PostAdmin(admin.ModelAdmin):
    # fields display on change list
    list_display = ['title', 'description']
    # fields to filter the change list with
    list_filter = ['published', 'created']
    # fields to search in change list
    search_fields = ['title', 'description', 'content']
    # enable the date drill down on change list
    date_hierarchy = 'created'
    # enable the save buttons on top on change form
    save_on_top = True
    # prepopulate the slug from the title - big timesaver!
    prepopulated_fields = {"slug": ("title",)}

admin.site.register(Post, PostAdmin)

create site

This is a 3 step process, explained in the next chapters.

writing urlpatterns

They are located in the klopt/urls.py file. And they contain some regular expressions that get matched in sequence, so be sure to leave the admin ones at the top so they don't get matched against the one we are going to add :

urls
1
2
3
4
5
urlpatterns = patterns('',
    url(r'^admin/', include(admin.site.urls)),
    url(r'^$', 'testapp.views.index'),
    url(r'^(?P<slug>[w-]+)/$', 'testapp.views.post'),
    )

It will be these regular expressions that lead you to the testapp.views.post site.

TODO: explain ^(?P[w-]+)/$

Write the views functions

Edit the file testapp/views.py and fill it like this :

views
from django.shortcuts import render, get_object_or_404
from testapp.models import Post

def index(request):
    # get the blog posts that are published
    posts = Post.objects.filter(published=True)
    # now return the rendered template
    return render(request, 'testapp/index.html', {'posts': posts})

def post(request, slug):
    # get the Post object
    post = get_object_or_404(Post, slug=slug)
    # now return the rendered template
    return render(request, 'testapp/post.html', {'post': post})

It creates two views for index and post, and points them to two templates, which will be created in the next chapter.

create templates

The templates just mentioned will be placed under the directory klopt/templates, it does not exist yet, so create it with :

templates
mkdir -p klopt/klopt/templates/testapp

You can place it wherever you want because you will need to set the directory yourself in settings.py :

dirs
1
2
3
TEMPLATE_DIRS = (
        '/path/to/your/templates',
)

This has to be an absolute path.

Now first create a base template, it will be one that all others will inherit from:

This file is placed in the top directory klopt/klopt/templates/base.html

template
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>
            {% block title %}{% endblock %}
        </title>
        </head>
    <body>
        <div class="content">
            {% block content %}
            {% endblock %}
        </div>
    </body>
</html>

So this will be the overall layout of the site, as you guess the {% %} tagged strings will be replaced by django. Now create the two templates specified earlier based on base.html.

index
klopt/klopt/templates/index.html

This is the template for the main page, index.html seems a legit name. It lists all blogs, with a title above it. It seems all readable to me.

As you see in the first line, it extends base.html.

The tags are :

  • {% tag %} is a template tag, like 'extends'
  • {{variable}} is a template variable, like {{post.title}}
  • {{variabledate:"c"}}

The other one template :

post
klopt/klopt/templates/post.html

Describes a post if clicked on :

template
{% extends 'base.html' %}

{% block title %}{{post.title}}{% endblock %}

{% block content %}
<article>
    <header>
        <h1> {{post.title}} </h1>
        <p>
            Posted on
            <time datetime="{{post.created|date:"c"}}">
            {{post.created|date}}
            </time>
        </p>
    </header>
    <p class="description">
        {{post.description}}
    </p>
    {{post.content|safe}}
</article>
{% endblock %}

adding style

Create a static directory for that :

style
mkdir klopt/klopt/static

And put a style.css in it. You can then load it with a line like this in base.html :

link
<link rel="stylesheet" type="text/css" href="{{STATIC_URL}}style.css">

apache install

Of course we want a real webserver underneath this. So here is how to run django on apache2.

apache2
apt-get install libapache2-mod-wsgi
a2enmod wsgi

This is the web server gateway interface. Which is the standard gateway for we applications written in python.

Add a file for called django in /etc/apache2/sites-available with this content

wsgi
1
2
3
4
5
6
7
8
9
WSGIScriptAlias /doc /var/www/django/klopt/klopt/wsgi.py
WSGIPythonPath /var/www/django/klopt

<Directory /var/www/django/klopt>
<Files wsgi.py>
Order deny,allow
Allow from all
</Files>
</Directory>

Also run a2ensite django to activate it That is if you installed the django directory with :

project
cd /var/www/django
django-manage startproject klopt

Enable :

enable
a2ensite django
service apache2 reload

Now you should have a connection at http://localhost/planner. You can still run the test server, it is on another port.

mongodb

Out of the box, django only has 4 types of underlying database, postgres, mysql, sqlite and oracle. If you want mongodb you will need to do more:

Installing django

Preliminaries: you will want virtualenv installed and make your project a virtual environment. It is to not mess up the already installed apps.

installing
1
2
3
4
pip install virtualenv
django-admin startproject mongoprojects
virtualenv mongoprojects
source mongoprojects/bin/activate

Then install nonrel and django toolbox.

nonrel
1
2
3
pip install git+https://github.com/django-nonrel/django@nonrel-1.5
pip install git+https://github.com/django-nonrel/djangotoolbox
pip install git+https://github.com/django-nonrel/mongodb-engine

troubleshooting

'url' requires a non-empty first argument.

This error, while using the {% url %} tag in django templates.

symptom

When using a tag like this :

tag
{{page.display}}

When the matched url was created like this :

url
url(r'^show/index/(?P[^/]+)/$','kloptwiki.views.read_page',name='showpage'),

diagnose

This line worked before, but i probably updated django to a version above 1.3 while installing other software. The version where this (suddenly) occurred was 1.4.5-1+dev7u4. Anyway it seems that django above 1.3 interprets showpage in the line as a variable (empty of course) instead of the matching name.

cure

Well, it's easy really, quote 'showpage' (or "showpage") and it will definitely be regarded as a string :

done
{{page.display}}

django syntax highlighting

This can be done with python-pygments. But most guides on installing it are very obscure on what's exactly happening. So here is a more elaborate guide. Also.. start using code tags instead of pre tags from now on..;)

preliminaries

These are the packages needed as stated in some guides:

preliminaries
apt-get install python-pygments python-beautifulsoup python-markdown

creating a django module

Make a directory called templatetags at project level, so in the directory containing manage.py. 'templatetags' will be the name of your module. To make python/django know it is meant as a module create an empty init.py in that directory :

create module
mkdir templatetags
touch templatetags/__init__.py

Then make a file called templatetags/filterlib.py containing this code :

templatetags
from django import template
from django.template.defaultfilters import stringfilter

from django.conf import settings

register = template.Library()

@register.filter(name='markdown')
@stringfilter
def markdown(value, arg=''):
    """
    Filter to create HTML out of Markdown, using custom extensions.

    The diffrence between this filter and the django-internal markdown
    filter (located in ``django/contrib/markup/templatetags/markup.py``)
    is that this filter enables extensions to be load.

    Usage::

        {{ object.text|markdown }}
        {{ object.text|markdown:"save" }}
        {{ object.text|markdown:"codehilite" }}
        {{ object.text|markdown:"save,codehilite" }}

    This code is taken from
    http://www.freewisdom.org/projects/python-markdown/Django
    """
    try:
        import markdown
    except ImportError:
        if settings.DEBUG:
            raise (template.TemplateSyntaxError,
                   "Error in {% markdown %} filter: "
                   + "The markdown library isn't installed.")
        else :
            from django.utils.html import escape, linebreaks
            return linebreaks(escape(value))
    else:
        extensions=arg.split(",")
        if len(extensions) > 0 and extensions[0] == "safe" :
            extensions = extensions[1:]
            safe_mode = True
        else :
            safe_mode = False
        return markdown.markdown(value, extensions, safe_mode=safe_mode)

You should now be able to include this new model in your templates with a line like this :

{% load filterlib.py %} {{ comment.commentmarkdown }}

Should because the guide was not complete, but i let that problem slip to point out the way to detect an error like that. The code just gives a vague error that it can't load filterlib. To get more info try loading it through the manage.py shell :

./manage.py shell >>> from templatetags import filterlib ImportError: No module named bs4

Now that's more like it. Searching aptitude reveals there is a python-bs4 as well, and after installing that, the import succeeds, so retry the django example.

A new problem arises :

templatetags.filterlib' is not a valid tag library: Template library templatetags.filterlib not found, tried django.templatetags.templatetags.filterlib,django.contrib.staticfiles.templatetags.templatetags.filterlib, django.contrib.comments.templatetags.templatetags.filterlib,django.contrib.admin.templatetags.templatetags.filterlib

As you see django looks in django.xxx for the templatetags module we created. This is a default behavior. The problem here was that i assumed that the templatetags should be added at the top level, as a new application as it where. However this is not the way it should be done, move the templatetags directory under the application on which you want to use it, in my case kloptwiki :

mv templatetags kloptwiki

syntax boxes

Always check the output of the syntax coloring, because this has an annoying way of showing it cannot parse the code in some cases. It will put red boxes around the points of error. While annoying if you are in a hurry and just want it to make the best of it, they are helpful in finding the problem.

If you are in a hurry, try removing the :::html specification above the code and let codehilite try to figure it out for itself. In many cases (for instance html code with mod_python tags in it) it does much better without the ::: line.

As with the front page, here is an example of how you should reference a page within a page of this django site :

links
[django](/doc/show/index/django/)
  • So the caption between [] just as normal links
  • the url between () directly after that, just as normal links.
  • but the page should be prefixed with /doc/show/index/ and closed with /
  • NO quotes

This particular error when installing a django site under apache2 :

Error

ImportError: No module named django.core.wsgi

Is cause by the wrong wsgi module for apache2. You can verify it by printing print(sys.path) in the wsgi.py module of your django app. It will show all sort of python2 paths.

Solution :

reinstall
sudo apt-get remove libapache2-mod-python libapache2-mod-wsgi
sudo apt-get install libapache2-mod-wsgi-py3