Django CRUD Parent/Child Edition

I’ve written before about implementing CRUD operations on a single table in Django, and the post was very popular on my blog and I hope many people learned something from it.

The next logical step is to write a CRUD application with Parent/Child relationship, the application is bit more verbose but it follow the same simple logic used in the first post.

In fact I didn’t write a single application, I wrote five stand alone applications that shows different ways to implement CRUD operations:

  • books_simple: Single table CRUD operations.
  • books_pc_formset: Parent/Child CRUD operation using Django formsets, which means editing the children in the sample form as the parent.
  • books_pc_formset2: similar to previous app but uses a foreign key in the children.
  • books_pc_multiview: Parent/Child CRUD operation using multiple one view for the parent and another seperate view for the children.
  • books_pc_multiview2: similar to previous app but uses a foreign key in the children.

You can find the code here:
https://github.com/rayed/django-crud-parent-child

Hope you find it useful, and please let me know if it needs any improvements.

Git directory outside working directory

I have an old PHP website that I wanted to have its code/content versioned with Git, normally Git setup the repo directory in the “.git” directory inside the working directory, but I faced a problem, if the working directory is accessible from the web server it means “.git” is also accessible too.

Luckily git have an option to have the repo directory located somewhere else using the GIT_DIR environment variable, so here what I did:


$ vi .profile
GIT_DIR=/home/rayed/my_website_git
GIT_WORK_TREE=/var/www/my_website
export GIT_DIR
export GIT_WORK_TREE

You notice that the web site is located in “/var/www/my_website” but the repo is located under totally different directory “/home/rayed/my_website_git”, so the web server can’t access it by mistake.

Django Themes (or where to put base.html?)

The Wrong Way

I used to create a new directory to hold common templates like “base.html”, and add it TEMPLATES_DIR in the settings.py file:

TEMPLATE_DIRS = (os.path.join(BASE_DIR, 'templates') ,)

But in most cases the “base.html” would need to use CSS, JS, and image files to be functional, so I changed the url routing to access them (from the DEBUG mode only), something like:

$ vi apps/urls.py
:
# Serve Static Files 
from django.conf import settings
from django.conf.urls.static import static
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
    urlpatterns += patterns('django.views.static',
        url(r'^(?P<path>(js|css|img)/.*)$', 'serve', {'document_root':  settings.BASE_DIR+'/../www'}),
        )

This setup isn’t ideal for many reasons:

  • I had to modify settings.py and urls.py with complicated settings.
  • Theme design span multiple directories, and it isn’t self contained.
  • Switching the design is complicated, and include many changes.

Django Simple Themes

Nowadays I create a new Django application e.g. “my_theme” to hold my “base.html” template and all needed static files (CSS, JS, Images, etc …).

./manage.py startapp my_theme

Then add it to INSTALLED_APPS:

INSTALLED_APPS = (
    # django core apps ...
    'my_theme',
    # other apps ...
)

The directory structure for my new app looks like this:

my_theme/
    templates/
        base.html
    static/
        my_theme/
            css/
            js/
            img/

and from my “base.html” (or any other template) I could access the static file using the static tag:

{% load staticfiles %}
<img src="{% static "my_theme/img/logo.png" %}" />

I don’t even need to change the “urls.py” file to access the static file, since the development server (i.e. ./manage.py runserver) already knows how to find them.

But for production I have to define:

STATIC_ROOT = os.path.join(BASE_DIR, '../www/static')

and run:

./manage.py collectstatic --noinput

New Theme

By having all theme files inside an application I can start new theme by copying “my_theme” to something like “new_theme” and replace it in the INSTALLED_APPS in the settings.py.

What about uploaded files?

To access uploaded file from development server you need to define both MEDIA_URL and MEDIA_ROOT and change your “urls.py”:

$ vi apps/urls.py
:
from django.conf import settings
from django.conf.urls.static import static
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Source: Serving files uploaded by a user during development

Sample Theme

You can download my sample theme from:
https://github.com/rayed/django_theme

Translation in Django

Settings

In your project “settings.py” setup the following values:

LOCALE_PATHS = (
    os.path.join(BASE_DIR, 'locale'),
    )
LANGUAGE_CODE = 'ar'

Here we defined the location of our translation files, by default Django will look for it under application directories under “locale” directory, but here we define it for the whole project.

The LANGUAGE_CODE line define a fixed translation to Arabia “ar”.

Source Code

For Python source code Django uses “ugettext” function aliased as “_” (underscore) to translate text strings:

from django.utils.translation import ugettext as _
from django.http import HttpResponse
from django.shortcuts import render

def page1(request):
    output = _("Welcome to my site.")
    return HttpResponse(output)

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

Template

Inside Django templates, Django uses trans template tag with the text to translate, don’t forget to load the tag using “{% load i18n %}”

{% load i18n %}

<h1>{% trans "Hello World" %}</h1>

Commands

After preparing the code we the following steps:

  • Collect translation string using “django-admin.py makemessages” command.
  • Edit the translation file “django.po”
  • Compile the translation to “django.mo”.

$ cd project_home

# Make the "locale" directory to store translation data
$ mkdir locale

# scan the project for translation strings
$ django-admin.py makemessages -l ar

# Edit the translation file and add your translation
$ vi locale/ar/LC_MESSAGES/django.po
:
msgid "Hello World"
msgstr "مرحبا يا عالم"
:

# compile django.po to django.mo
$ django-admin.py compilemessages

That’s it, you should be able to see your applications translated!

Implementing Login/Logout in Django

Update: add names and namespace to URLs

Implementing user authentication is fairly easy job in Django, many functionalities are already included in the standard Django installation, you can manage users using the default “admin” app the comes with Django.

Here I will show how implement Login/Logout feature by relying on Django built-in views.

Steps:

  • Create “accounts” app: we will put all “accounts” related files in this app.
  • Create URL mapping for login and logout pages.
  • Include “accounts” URL in the main URL mapping.
  • Create login page HTML template
  • Add small template code to show current user in all pages (changing base template)

# Create "accounts" app
$ ./manage.py startapp accounts
# Add to INSTALLED_APPS
$ vi project_name/settings.py 
INSTALLED_APPS = (
  :
  'accounts',
  :
)


# Create URL mapping for login and logout pages
$ vi accounts/urls.py 
from django.conf.urls import patterns, url
urlpatterns = patterns('',
    url(
        r'^login/$',
        'django.contrib.auth.views.login',
        name='login',
        kwargs={'template_name': 'accounts/login.html'}
    ),
    url(
        r'^logout/$',
        'django.contrib.auth.views.logout',
        name='logout',
        kwargs={'next_page': '/'}
    ),
)

# Include "accounts" URL in the main URL mapping
$ vi project_name/urls.py 
urlpatterns = patterns('',
    :
    url(r'^accounts/', include('accounts.urls', namespace='accounts')),
    :
)


# Create login page HTML template
$ vi templates/accounts/login.html
{% extends "base.html" %}
{% block content %}
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
<form method="post" action="{% url 'accounts:login' %}">
{% csrf_token %}
<table>
{{ form }}
</table>
<input type="submit" value="login" />
<input type="hidden" name="next" value="/" />
</form>
{% endblock %}


# Add small template code to show current user
$ vi template/base.html
:
{% if user.is_authenticated %}
    <p>Welcome, {{ user.username }}  <a href="{% url 'accounts:logout' %}">[logout]</a></p>
{% else %}
    <p>Welcome, Guest <a href="{% url 'accounts:login' %}">[login]</a></p>
{% endif %}
:

For more on the subject:
Using the Django authentication system

Bonus: Password Change form

Continue reading Implementing Login/Logout in Django

Arabic Projects Ideas 2: Open Arabic Fonts

If you build Arabic website you must be hit by the hard reality, Arabic web font options are really narrow, the only realistic choices are:

  • Tahoma: only good for small sizes.
  • Arabic Transparent
  • Traditional Arabic

My idea is to buy other quality Arabic fonts and ask browser/OS vendors to include them, we really need more choice to improve the quality of website productions, and add more creativity to our Arabic Internet.

The idea came after I read something from Jihad Alammar, and Web fonts now (how we’re doing with that)

If you have an ideas to improve the initial idea please comment.