Django “anonymous_required” decorator

Posted on Wednesday, January 6th, 2010 under , ,

I like Django’s login_required decorator. It’s a clean and simple way to allow and/or deny un-logged-in users to access parts of the website. But I also felt the need for a decorator to allow me to restrict access to some views only to non logged-in users. For instance, if an user in logged in, it should be denied access to views like /accounts/register or /accounts/login and redirected to his/her profile.

I’ve looked for one on the web, but couldn’t find anything suitable to my needs, so I’ve wrote my own:

from django.http import HttpResponseRedirect
 
def anonymous_required( view_function, redirect_to = None ):
    return AnonymousRequired( view_function, redirect_to )
 
class AnonymousRequired( object ):
    def __init__( self, view_function, redirect_to ):
        if redirect_to is None:
            from django.conf import settings
            redirect_to = settings.LOGIN_REDIRECT_URL
        self.view_function = view_function
        self.redirect_to = redirect_to
 
    def __call__( self, request, *args, **kwargs ):
        if request.user is not None and request.user.is_authenticated():
            return HttpResponseRedirect( self.redirect_to ) 
        return self.view_function( request, *args, **kwargs )

It’s also available on Django Snippets. Its usage is quite simple:

@anonymous_required
def my_view( request ):
    return render_to_response( 'my-view.html' )

That’s about it!

Django configuration file

Posted on Monday, December 28th, 2009 under , ,

django web frameworkI’ve been using Django for quite some time now and I kind of like it. It provides a fast – really fast – and clean way of doing things. When I first started with Django, I’ve used it mainly for simpler projects and kept the larger, more complicated ones on Zend Framework. That’s because I feel much more comfortable with PHP and Zend Framework rather than python and Django.

But, lately, I’ve used django for more ambitious projects and some obvious flaws began to annoy me. The first thing – the one this entry’s about – is the configuration file. Django comes with a settings.py file in which all the settings are being held, without any regard to their purpose.

Environment settings like database connection strings, file system paths and debuging are mixed together with application settings like what middleware classes are used, context processors and so on. So I’ve decided to split the configuration file in two, like in the following example:

local.py

This file holds the host related configuration and each instance of the application should have its own local.py file. One for development, one for testing, one for staging, one for production and so on. This file should not be included in the source control repository, so add a svn/git/whatever ignore on it.

# debug settings
DEBUG = True
TEMPLATE_DEBUG = DEBUG
 
# database configuration
DATABASE_ENGINE = ''
DATABASE_NAME = ''
DATABASE_USER = ''
DATABASE_PASSWORD = ''
DATABASE_HOST = ''
DATABASE_PORT = ''
 
# media root ex: /var/www/my-project/media
MEDIA_ROOT = ''
 
# media url ex: media.my-project.tld
MEDIA_URL = ''
 
# admin media url ex: /media
ADMIN_MEDIA_PREFIX = '/media/'
 
# application's secret key
SECRET_KEY = 'mY-S3Cr3t-K3y-m|_|st-b3-un1QuE-4nD-h4rD-t0-GueSs'

settings.py

This file holds the application related configurations and should be included in the version control system.

import os
 
# root directory for the project
ROOT_DIR = os.path.realpath( os.path.dirname( __file__ ) )
 
ADMINS = (
	( 'root', 'root@project.tld' ),
)
 
# import all the local settings
from local import *
 
MANAGERS = ADMINS
TIME_ZONE = 'Europe/Bucharest'
 
LANGUAGE_CODE = 'en-us'
 
SITE_ID = 1
 
USE_I18N = True
 
TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.load_template_source',
    'django.template.loaders.app_directories.load_template_source',
)
 
MIDDLEWARE_CLASSES = (
    'django.middleware.cache.UpdateCacheMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.middleware.cache.FetchFromCacheMiddleware',
)
 
ROOT_URLCONF = 'my-project.urls'
 
TEMPLATE_CONTEXT_PROCESSORS = (
    'django.core.context_processors.auth',
    'django.core.context_processors.debug',
    'django.core.context_processors.i18n',
    'django.core.context_processors.media',
)
 
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
)
 
# template directories
TEMPLATE_DIRS = (
    os.path.join( ROOT_DIR, 'templates' ),
    os.path.join( ROOT_DIR, 'other', 'template', 'path' ),
)
 
# django debug toolbar configuration
INTERNAL_IPS = ( '127.0.0.1' )
if DEBUG:
    MIDDLEWARE_CLASSES += 'debug_toolbar.middleware.DebugToolbarMiddleware', 
    INSTALLED_APPS += 'debug_toolbar',

The last bit is because I usually use in development the incredibly useful Django debug_toolbar, and of course, I want it turned off on the live environment.

Django…for the very first time

Posted on Thursday, July 2nd, 2009 under ,

django web frameworkThis is a post I’ve wanted to write for quite some time now, but there is so much say that I couldn’t get the time to write it all down. So I’ve decided to split the first impression on django topic into smaller articles, this being the first post from a longer django series.

I did some projects with python lately, and I like the language a lot, but none of them were involved building web pages. Some vim scripts, some automatization scripts or web crawlers. But not a single web script. Usually a company doesn’t switch easily from PHP to python, or to any other programming language, because of the costs involved (training, etc.), so it’s pretty hard to start a project on another framework. But here, things are a lot simpler. My job description consists of only 4 words: get the sh*t done. Aside from this, I have complete ownership of the projects I’m working on and I’m free to choose whatever technology I please.

Prerequisites

Installing django is a piece of cake. Just follow the instructions on their site and it works like a charm. If you’re using python 2.6, you will receive some warnings concerning the MySQLdb package which uses a deprecated package. Just ignore them, at least until you decide to upgrade to python 3.0 ;)

Preparing the editor. I use vim for editing and I needed something to help me out with code completion, mainly because I’m lazy and don’t like to type long name, and second because I don’t know all the django’s components’ names by hard. I’ve tried pysmell, but it didn’t worked well, and, since it’s marked as experimental, I don’t think it is supposed to. So I’ve tried good ol’ ctags. This is my recommendation. To create a ctags index, simply type:

ctags -R -f ~/.vim/tags/python.ctags /usr/local/lib/python2.6/dist-packages

and in Vim

set tags+=$HOME/.vim/tags/python.ctags

And voila. It works. If you’re using python 2.5 use the appropriate path.

What I like about django

The admin. It rules, it’s simple to customise, it saves a lot of time. I love it. Back in the days, when I was using CakePHP, I’ve often wished that its scaffolding system did what django’s admin does now. I also love the authentication system. It is another well built component that saves a lot of time of routine work. The models – not having to write SQL statements by hand all the time gives me a hard-on. They also provide a logical separation between a single model object (which encapsulates a row in the table) and the statically declared information retrieval methods.

What I don’t like about django

The implementation of the MVC pattern is a little bit strange. They call it MVT (Model View Template), where “the view” is basically a controller’s action in the “traditional” MVC approach, and “the template” is what you’d expect to be the view.

It offers decent degree of logic separation, I don’t like it though that the action and method attributes are being set in the view…template. No one can tell me that where a form sends its data is presentation logic that should reside in a template.

The code generation scripts don’t always work in the way that you’d expect, for instance, if you change something in a model and run the

python manage.py sql myApp
python manage.py syncdb

sequence and the table already exists, it won’t update it. And I hate the template system. Really do. I don’t get its purpose – I don’t get any templating system’s purpuse – and some things in it are really weird. I mean ifequal…hello? Not exactly syntactic sugar :P

Conclusion

I like django, as it provides a quick and clean way of doing things. I will definitely use it in the future, possibly in my next project, so stay tuned for more django articles :P