[ACCEPTED]-Favorite Django Tips & Features?-hidden-features

Accepted answer
Score: 221

I'm just going to start with a tip from 6 myself :)

Use os.path.dirname() in settings.py to avoid hardcoded dirnames.

Don't hardcode path's in your settings.py 5 if you want to run your project in different 4 locations. Use the following code in settings.py 3 if your templates and static files are located 2 within the Django project directory:

# settings.py
import os
PROJECT_DIR = os.path.dirname(__file__)
STATIC_DOC_ROOT = os.path.join(PROJECT_DIR, "static")
    os.path.join(PROJECT_DIR, "templates"),

Credits: I 1 got this tip from the screencast 'Django From the Ground Up'.

Score: 128

Install Django Command Extensions and pygraphviz and then issue the following 2 command to get a really nice looking Django 1 model visualization:

./manage.py graph_models -a -g -o my_project.png
Score: 119

Use django-annoying's render_to decorator instead of render_to_response.

def foo(request):
    bars = Bar.objects.all()
    if request.user.is_authenticated():
        return HttpResponseRedirect("/some/url/")
        return {'bars': bars}

# equals to
def foo(request):
    bars = Bar.objects.all()
    if request.user.is_authenticated():
        return HttpResponseRedirect("/some/url/")
        return render_to_response('template.html',
                              {'bars': bars},

Edited to point 3 out that returning an HttpResponse (such 2 as a redirect) will short circuit the decorator 1 and work just as you expect.

Score: 101

There's a set of custom tags I use all over 12 my site's templates. Looking for a way to 11 autoload it (DRY, remember?), I found the 10 following:

from django import template

If you put this in a module that's 9 loaded by default (your main urlconf for 8 instance), you'll have the tags and filters 7 from your custom tag module available in 6 any template, without using {% load custom_tag_module %}.

The argument 5 passed to template.add_to_builtins() can be any module path; your 4 custom tag module doesn't have to live in 3 a specific application. For example, it 2 can also be a module in your project's root 1 directory (eg. 'project.custom_tag_module').

Score: 96

Virtualenv + Python = life saver if you are working 3 on multiple Django projects and there is 2 a possibility that they all don't depend 1 on the same version of Django/an application.

Score: 87

Don't hard-code your URLs!

Use url names instead, and 7 the reverse function to get the URL itself.

When 6 you define your URL mappings, give names 5 to your URLs.

urlpatterns += ('project.application.views'
   url( r'^something/$', 'view_function', name="url-name" ),

Make sure the name is unique 4 per URL.

I usually have a consistent format 3 "project-appplication-view", e.g. "cbx-forum-thread" for 2 a thread view.

UPDATE (shamelessly stealing ayaz's addition):

This 1 name can be used in templates with the url tag.

Score: 81

Use django debug toolbar. For example, it allows to view all 3 SQL queries performed while rendering view 2 and you can also view stacktrace for any 1 of them.

Score: 79

Don't write your own login pages. If you're 4 using django.contrib.auth.

The real, dirty 3 secret is that if you're also using django.contrib.admin, and 2 django.template.loaders.app_directories.load_template_source 1 is in your template loaders, you can get your templates free too!

# somewhere in urls.py
urlpatterns += patterns('django.contrib.auth',
    (r'^accounts/login/$','views.login', {'template_name': 'admin/login.html'}),
Score: 66

Context processors are awesome.

Say you have a different user model and 23 you want to include that in every response. Instead 22 of doing this:

def myview(request, arg, arg2=None, template='my/template.html'):
    ''' My view... '''
    response = dict()
    myuser = MyUser.objects.get(user=request.user)
    response['my_user'] = myuser
    return render_to_response(template,

Context processes give you 21 the ability to pass any variable to your templates. I 20 typically put mine in 'my_project/apps/core/context.py:

def my_context(request):
        return dict(my_user=MyUser.objects.get(user=request.user))
    except ObjectNotFound:
        return dict(my_user='')

In your settings.py add the 19 following line to your TEMPLATE_CONTEXT_PROCESSORS


Now every time a 18 request is made it includes the my_user key automatically.

Also signals win.

I 17 wrote a blog post about this a few months 16 ago so I'm just going to cut and paste:

Out 15 of the box Django gives you several signals 14 that are incredibly useful. You have the 13 ability to do things pre and post save, init, delete, or 12 even when a request is being processed. So 11 lets get away from the concepts and demonstrate 10 how these are used. Say we’ve got a blog

from django.utils.translation import ugettext_lazy as _
class Post(models.Model):
    title = models.CharField(_('title'), max_length=255)
    body = models.TextField(_('body'))
    created = models.DateTimeField(auto_now_add=True)

So 9 somehow you want to notify one of the many 8 blog-pinging services we’ve made a new post, rebuild 7 the most recent posts cache, and tweet about 6 it. Well with signals you have the ability 5 to do all of this without having to add 4 any methods to the Post class.

import twitter

from django.core.cache import cache
from django.db.models.signals import post_save
from django.conf import settings

def posted_blog(sender, created=None, instance=None, **kwargs):
    ''' Listens for a blog post to save and alerts some services. '''
    if (created and instance is not None):
        tweet = 'New blog post! %s' instance.title
        t = twitter.PostUpdate(settings.TWITTER_USER,
        cache.set(instance.cache_key, instance, 60*5)
       # send pingbacks
       # ...
       # whatever else
post_save.connect(posted_blog, sender=Post)

There we go, by 3 defining that function and using the post_init 2 signal to connect the function to the Post 1 model and execute it after it has been saved.

Score: 58

When I was starting out, I didn't know that 2 there was a Paginator, make sure you know of its 1 existence!!

Score: 46

Use IPython to jump into your code at any level 8 and debug using the power of IPython. Once 7 you have installed IPython just put this 6 code in wherever you want to debug:

from IPython.Shell import IPShellEmbed; IPShellEmbed()()

Then, refresh 5 the page, go to your runserver window and 4 you will be in an interactive IPython window.

I 3 have a snippet set up in TextMate so I just 2 type ipshell and hit tab. I couldn't live 1 without it.

Score: 43

Run a development SMTP server that will 3 just output whatever is sent to it (if you 2 don't want to actually install SMTP on your 1 dev server.)

command line:

python -m smtpd -n -c DebuggingServer localhost:1025
Score: 41

From the django-admin documentation:

If you use the Bash shell, consider 4 installing the Django bash completion script, which 3 lives in extras/django_bash_completion in the Django distribution. It 2 enables tab-completion of django-admin.py and manage.py commands, so 1 you can, for instance...

  • Type django-admin.py.
  • Press [TAB] to see all available options.
  • Type sql, then [TAB], to see all available options whose names start with sql.
Score: 40

The ./manage.py runserver_plus facilty which comes with django_extensions is truly 11 awesome.

It creates an enhanced debug page 10 that, amongst other things, uses the Werkzeug 9 debugger to create interactive debugging 8 consoles for each point in the stack (see 7 screenshot). It also provides a very useful 6 convenience debugging method dump() for displaying 5 information about an object/frame.

enter image description here

To install, you 4 can use pip:

pip install django_extensions
pip install Werkzeug

Then add 'django_extensions' to your INSTALLED_APPS tuple in 3 settings.py and start the development server with the 2 new extension:

./manage.py runserver_plus

This will change the way you 1 debug.

Score: 37

I like to use the Python debugger pdb to 2 debug Django projects.

This is a helpful 1 link for learning how to use it: http://www.ferg.org/papers/debugging_in_python.html

Score: 37

When trying to exchange data between Django 3 and another application, request.raw_post_data is a good friend. Use 2 it to receive and custom-process, say, XML 1 data.

Documentation: http://docs.djangoproject.com/en/dev/ref/request-response/

Score: 36

Use Jinja2 alongside Django.

If you find the Django 15 template language extremely restricting 14 (like me!) then you don't have to be stuck 13 with it. Django is flexible, and the template 12 language is loosely coupled to the rest 11 of the system, so just plug-in another template 10 language and use it to render your http 9 responses!

I use Jinja2, it's almost like a powered-up 8 version of the django template language, it 7 uses the same syntax, and allows you to 6 use expressions in if statements! no more 5 making a custom if-tags such as if_item_in_list! you can 4 simply say %{ if item in list %}, or {% if object.field < 10 %}.

But that's not all; it 3 has many more features to ease template 2 creation, that I can't go though all of 1 them in here.

Score: 35

Add assert False in your view code to dump debug information.


Score: 34

This adds to the reply above about Django URL names and reverse URL dispatching.

The 3 URL names can also be effectively used within 2 templates. For example, for a given URL 1 pattern:

url(r'(?P<project_id>\d+)/team/$', 'project_team', name='project_team')

you can have the following in templates:

<a href="{% url project_team project.id %}">Team</a>
Score: 27

Since Django "views" only need to be callables 9 that return an HttpResponse, you can easily 8 create class-based views like those in Ruby 7 on Rails and other frameworks.

There are 6 several ways to create class-based views, here's 5 my favorite:

from django import http

class RestView(object):
    methods = ('GET', 'HEAD')

    def dispatch(cls, request, *args, **kwargs):
        resource = cls()
        if request.method.lower() not in (method.lower() for method in resource.methods):
            return http.HttpResponseNotAllowed(resource.methods)
            method = getattr(resource, request.method.lower())
        except AttributeError:
            raise Exception("View method `%s` does not exist." % request.method.lower())
        if not callable(method):
            raise Exception("View method `%s` is not callable." % request.method.lower())
        return method(request, *args, **kwargs)

    def get(self, request, *args, **kwargs):
        return http.HttpResponse()

    def head(self, request, *args, **kwargs):
        response = self.get(request, *args, **kwargs)
        response.content = ''
        return response

You can add all sorts of other 4 stuff like conditional request handling 3 and authorization in your base view.

Once 2 you've got your views setup your urls.py 1 will look something like this:

from django.conf.urls.defaults import *
from views import MyRestView

urlpatterns = patterns('',
    (r'^restview/', MyRestView.dispatch),
Score: 21

Instead of using render_to_response to bind your context to 16 a template and render it (which is what 15 the Django docs usually show) use the generic 14 view direct_to_template. It does the same thing that render_to_response does 13 but it also automatically adds RequestContext 12 to the template context, implicitly allowing 11 context processors to be used. You can do 10 this manually using render_to_response, but why bother? It's 9 just another step to remember and another 8 LOC. Besides making use of context processors, having 7 RequestContext in your template allows you 6 to do things like:

<a href="{{MEDIA_URL}}images/frog.jpg">A frog</a> 

which is very useful. In 5 fact, +1 on generic views in general. The 4 Django docs mostly show them as shortcuts 3 for not even having a views.py file for 2 simple apps, but you can also use them inside 1 your own view functions:

from django.views.generic import simple

def article_detail(request, slug=None):
    article = get_object_or_404(Article, slug=slug)
    return simple.direct_to_template(request, 
        extra_context={'article': article}
Score: 20

I don't have enough reputation to reply 7 to the comment in question, but it's important 6 to note that if you're going to use Jinja, it 5 does NOT support the '-' character in template 4 block names, while Django does. This caused 3 me a lot of problems and wasted time trying 2 to track down the very obscure error message 1 it generated.

Score: 19

django.db.models.get_model does allow you to retrieve a model without 2 importing it.

James shows how handy it can 1 be: "Django tips: Write better template tags — Iteration 4 ".

Score: 19

The webdesign app is very useful when starting to design 2 your website. Once imported, you can add 1 this to generate sample text:

{% load webdesign %}
{% lorem 5 p %}
Score: 19

Everybody knows there is a development server 13 you can run with "manage.py runserver", but 12 did you know that there is a development 11 view for serving static files (CSS / JS 10 / IMG) as well ?

Newcomers are always puzzled 9 because Django doesn't come with any way 8 to serve static files. This is because the 7 dev team think it is the job for a real 6 life Web server.

But when developing, you 5 may not want to set up Apache + mod_wisgi, it's 4 heavy. Then you can just add the following 3 to urls.py:

(r'^site_media/(?P<path>.*)$', 'django.views.static.serve',
        {'document_root': '/path/to/media'}),

Your CSS / JS / IMG will be available 2 at www.yoursite.com/site_media/.

Of course, don't 1 use it in a production environment.

Score: 18

I learned this one from the documentation 7 for the sorl-thumbnails app. You can use the "as" keyword 6 in template tags to use the results of the 5 call elsewhere in your template.

For example:

{% url image-processor uid as img_src %}
<img src="{% thumbnail img_src 100x100 %}"/>

This 4 is mentioned in passing in the Django templatetag 3 documentation, but in reference to loops 2 only. They don't call out that you can use 1 this elsewhere (anywhere?) as well.

Score: 16

django.views.generic.list_detail.object_list -- It provides all the logic & template 6 variables for pagination (one of those I've-written-that-a-thousand-times-now 5 drudgeries). Wrapping it allows for any logic you 4 need. This gem has saved me many hours 3 of debugging off-by-one errors in my "Search 2 Results" pages and makes the view code 1 cleaner in the process.

Score: 16

PyCharm IDE is a nice environment to code and especially 1 debug, with built-in support for Django.

Score: 14

Use database migrations. Use South.


Score: 14

Use xml_models to create Django models that use an 13 XML REST API backend (instead of a SQL one). This 12 is very useful especially when modelling 11 third party APIs - you get all the same 10 QuerySet syntax that you're used to. You 9 can install it from PyPI.

XML from an API:

<profile id=4>

And 8 now in python:

class Profile(xml_models.Model):
    user_id = xml_models.IntField(xpath='/profile/@id')
    email = xml_models.CharField(xpath='/profile/email')
    first = xml_models.CharField(xpath='/profile/first_name')
    last = xml_models.CharField(xpath='/profile/last_name')
    birthday = xml_models.DateField(xpath='/profile/date_of_birth')

    finders = {
        (user_id,):  settings.API_URL +'/api/v1/profile/userid/%s',
        (email,):  settings.API_URL +'/api/v1/profile/email/%s',

profile = Profile.objects.get(user_id=4)
print profile.email
# would print 'joe@example.com'

It can also handle relationships 7 and collections. We use it every day in 6 heavily used production code, so even though 5 it's beta it's very usable. It also has 4 a good set of stubs that you can use in 3 your tests.

(Disclaimer: while I'm not the 2 author of this library, I am now a committer, having 1 made a few minor commits)

Score: 13

Just found this link: http://lincolnloop.com/django-best-practices/#table-of-contents - "Django Best 1 Practices".

Score: 12

Instead of evaluating whole queryset to 15 check whether you got back any results, use 14 .exists() in Django 1.2+ and .count() for 13 previous versions.

Both exists() and count() clears 12 order by clauses and retrieves a single 11 integer from DB. However exists() will always 10 return 1 where as count may return higher 9 values on which limits will be applied manually. Source 8 for has_result used in exists() and get_count used in count() for 7 the curious.

Since they both return a single 6 integer, there's no model instantiation, loading 5 model attributes in memory and no large 4 TextFields being passed between your DB 3 and app.

If you have already evaluated the 2 query, .count() computes len(cached_result) and 1 .exists() computes bool(cached_result)

Not efficient - Example 1

books = Books.objects.filter(author__last_name='Brown')
if books:
    # Do something

Not efficient - Example 2

books = Books.objects.filter(author__last_name='Brown')
if len(books):
    # Do something

Efficient - Example 1

books = Books.objects.filter(author__last_name='Brown')
if books.count():
    # Do something

Efficient - Example 2

books = Books.objects.filter(author__last_name='Brown')
if books.exists():
    # Do something
Score: 12

If you make changes into model

./manage.py dumpdata appname > appname_data.json  
./manage.py reset appname
django-admin.py loaddata appname_data.json


Score: 11

Use signals to add accessor-methods on-the-fly.

I 7 saw this technique in django-photologue: For any Size object 6 added, the post_init signal will add the 5 corresponding methods to the Image model. If 4 you add a site giant, the methods to retrieve 3 the picture in giant resolution will be 2 image.get_giant_url().

The methods are generated by calling add_accessor_methods from 1 the post_init signal:

def add_accessor_methods(self, *args, **kwargs):
    for size in PhotoSizeCache().sizes.keys():
        setattr(self, 'get_%s_size' % size,
                curry(self._get_SIZE_size, size=size))
        setattr(self, 'get_%s_photosize' % size,
                curry(self._get_SIZE_photosize, size=size))
        setattr(self, 'get_%s_url' % size,
                curry(self._get_SIZE_url, size=size))
        setattr(self, 'get_%s_filename' % size,
                curry(self._get_SIZE_filename, size=size))

See the source code of photologue.models for real-world usage.

Score: 11

Remove Database Access Information from settings.py

One thing I've done in my Django site's 34 settings.py is load database access info from a file 33 in /etc. This way the access setup (database 32 host, port, username, password) can be different 31 for each machine, and sensitive info like 30 the password isn't in my project's repository. You 29 might want to restrict access to the workers 28 in a similar manner, by making them connect 27 with a different username.

You could also 26 pass in the database connection information, or 25 even just a key or path to a configuration 24 file, via environment variables, and handle 23 it in settings.py.

For example, here's how I pull in 22 my database configuration file:

g = {}
dbSetup = {}
execfile(os.environ['DB_CONFIG'], g, dbSetup)
if 'databases' in dbSetup:
    DATABASES = dbSetup['databases']
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            # ...

Needless 21 to say, you need to make sure that the file 20 in DB_CONFIG is not accessible to any user besides 19 the db admins and Django itself. The default 18 case should refer Django to a developer's 17 own test database. There may also be a 16 better solution using the ast module instead 15 of execfile, but I haven't researched it yet.

Another 14 thing I do is use separate users for DB 13 admin tasks vs. everything else. In my 12 manage.py, I added the following preamble:

# Find a database configuration, if there is one, and set it in the environment.
adminDBConfFile = '/etc/django/db_admin.py'
dbConfFile = '/etc/django/db_regular.py'
import sys
import os
def goodFile(path):
    return os.path.isfile(path) and os.access(path, os.R_OK)
if len(sys.argv) >= 2 and sys.argv[1] in ["syncdb", "dbshell", "migrate"] \
    and goodFile(adminDBConfFile):
    os.environ['DB_CONFIG'] = adminDBConfFile
elif goodFile(dbConfFile):
    os.environ['DB_CONFIG'] = dbConfFile

Where the 11 config in /etc/django/db_regular.py is for a user with access to 10 only the Django database with SELECT, INSERT, UPDATE, and 9 DELETE, and /etc/django/db_admin.py is for a user with these permissions 8 plus CREATE, DROP, INDEX, ALTER, and LOCK 7 TABLES. (The migrate command is from South.) This 6 gives me some protection from Django code 5 messing with my schema at runtime, and it 4 limits the damage an SQL injection attack 3 can cause (though you should still check 2 and filter all user input).

(Copied from 1 my answer to another question)

Score: 9

Instead of running the Django dev server 9 on localhost, run it on a proper network 8 interface. For example:

python manage.py runserver


python manage.py runserver

Then you can not 7 only easily use Fiddler (http://www.fiddler2.com/fiddler2/) or another tool 6 like HTTP Debugger (http://www.httpdebugger.com/) to inspect your HTTP 5 headers, but you can also access your dev 4 site from other machines on your LAN to 3 test.

Make sure you are protected by a firewall 2 though, although the dev server is minimal 1 and relatively safe.

Score: 7

Use wraps decorator in custom views decorators 4 to preserve view's name, module and docstring. E.g.

    from functools import wraps
except ImportError:
    from django.utils.functional import wraps  # Python 2.3, 2.4 fallback.

def view_decorator(fun):
    def wrapper():
        # here goes your decorator's code
    return wrapper

Beware: will 3 not work on a class-based views (those with 2 __call__ method definition), if the author hasn't 1 defined a __name__ property. As a workaround use:

from django.utils.decorators import available_attrs
    @wraps(fun, assigned=available_attrs(fun))
Score: 7

The Django Debug Toolbar is really fantastic. Not really a toolbar, it 5 actually brings up a sidepane that tells 4 you all sorts of information about what 3 brought you the page you're looking at - DB 2 queries, the context variables sent to the 1 template, signals, and more.

Score: 6

Using an 'apps' folder to organize your 6 applications without editing PYTHONPATH

This 5 has come handy when I want to organize my 4 folders like this:


without overwritting PYTHONPATH 3 or having to add apps to every import like:

from apps.foo.model import *
from apps.bar.forms import *

In 2 your settings.py add

import os
import sys
PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
sys.path.insert(0, os.path.join(PROJECT_ROOT, "apps"))

and you are ready to 1 go :-)

I saw this at http://codespatter.com/2009/04/10/how-to-add-locations-to-python-path-for-reusable-django-apps/

Score: 5

Use reverse in your urlconf.

This is one 3 of those tricks where I don't understand 2 why it isn't the default.

Here's a link to 1 where I picked it up: http://andr.in/2009/11/21/calling-reverse-in-django/

Here's the code snippet:

from django.conf.urls.defaults import *
from django.core.urlresolvers import reverse
from django.utils.functional import lazy
from django.http import HttpResponse

reverse_lazy = lazy(reverse, str)

urlpatterns = patterns('',
url(r'^comehere/', lambda request: HttpResponse('Welcome!'), name='comehere'),
url(r'^$', 'django.views.generic.simple.redirect_to',
{'url': reverse_lazy('comehere')}, name='root')
Score: 5

Use djangorecipe to manage your project

  • If you're writing a new app, this recipe makes testing it outside of a project really easy
  • It allows you to manage dependencies for a project (e.g. what version of some app it should depend on)

All you have 28 to do to get started is this:

  1. Create a folder for your new website (or library)
  2. Create a buildout.cfg 27 with following content in it:

  3. Grab a bootstrap.py to get a local installation of buildout and place it within your directory. You can either go with the official one (sorry, Markdown didn't like part of the full link :-/ ) or with one that uses distribute instead of setuptools as described by Reinout van Rees.
  4. python bootstrap.py (or python bootstrap_dev.py if you want to use distribute).
  5. ./bin/buildout

That's it. You 26 should now have a new folder "my_new_site", which 25 is your new django 1.1.1 project, and in 24 ./bin you will find the django-script which replaces 23 the manage.py on a normal installation.

What's 22 the benefit? Let's say you want to use something 21 like django-comment-spamfighter in your 20 project. All you'd have to do is change 19 your buildout.cfg to something like this:



Note 18 that all I did was to add the last 2 lines 17 which say, that the django-part should also 16 have the django-comments-spamfighter package 15 in version 0.4. The next time you run ./bin/buildout, buildout 14 will download that package and modify ./bin/django 13 to add it to its PYTHONPATH.

djangorecipe 12 is also suited for deploying your project 11 with mod_wsgi. Just add the wsgi=true setting to 10 the django-part of your buildout.cfg and 9 a "django.wsgi" will appear in 8 your ./bin folder :-)

And if you set the 7 test option to a list of applications, the djangorecipe 6 will create a nice wrapper for you that 5 runs all the tests for the listed application 4 in your project.

If you want to develop a 3 single app in a standalone environment for 2 debugging etc., Jakob Kaplan-Moss has a 1 quite complete tutorial on his blog

Score: 5

Render form via django template instead of as_(ul|table|p)().

This article shows, how to use template 2 to render CusstomForms instead of as_p(), as_table()...

To 1 make it work change

  • from django import newforms as forms to from django import forms
  • from django.newforms.forms import BoundField to from django.forms.forms import BoundField
Score: 5

Automatically set 'DEBUG' attribute on production 1 environment (settings.py)

import socket

if socket.gethostname() == 'productionserver.com':
    DEBUG = False
    DEBUG = True

By: http://nicksergeant.com/2008/automatically-setting-debug-in-your-django-app-based-on-server-hostname/

Score: 4

Changing Django form field properties on init

Sometimes it's useful to pass extra arguments 1 to a Form class.

from django import forms
from mymodels import Group

class MyForm(forms.Form):

    def __init__(self,my_var,*args,**kwrds):
        self.fields['some_choices']=[[x,x] for x in list_of_stuff]

source: Dzone snippets

Score: 4

This is a really easy way to never have 14 to import another one of your models again 13 in your python shell.

First, install IPython (If 12 you don't use IPython, what's wrong with 11 you?). Next, create a python script, ipythonrc.py, in 10 your django project directory with the following 9 code in it:

from django.db.models.loading import get_models 
for m in get_models(): 
     globals()[m.__name__] = m 
#NOTE: if you have two models with the same name you'll only end up with one of them

Then, in your ~/.ipython/ipythonrc 8 file, put the following code in the "Python 7 files to load and execute" section:

execfile /path/to/project/ipythonrc.py

Now 6 every time you start up IPython or run ./manage.py shell you 5 will have all your models already imported 4 and ready to use. No need to ever import 3 another model again.

You can also put any 2 other code you execute a lot in your ipythonrc.py 1 file to save yourself time.

Score: 2

django_extensions from https://github.com/django-extensions/django-extensions is just great.

Few nice ./manage.py commands:

  • shell_plus - autoimports models from all INSTALLED_APPS
  • show_urls - prints all urls defined in all apps in project
  • runscript - runs any script in project context (you can use models and other Django-related modules)


Score: 2

PyCharm and Wingware IDE is great tool if 2 you have money to pay for the license.

Since 1 I am a poor developer, I use PyDev with Eclipse.

Score: 1

Create dynamic models for sets of legacy 7 tables with the same structure:

class BaseStructure(models.Model):
    name = models.CharField(max_length=100)
    address = models.CharField(max_length=100)

    class Meta:

class DynamicTable(models.Model):
    table_name = models.CharField(max_length=20)

    def get_model(self):
        class Meta:

        attrs = {}
        attrs['Meta'] = Meta

        # type(new_class_name, (base,classes), {extra: attributes})
        dynamic_class = type(self.table_name, (BaseStructure,), attrs) 
        return dynamic_class

customers = DynamicTable.objects.get(table_name='Customers').get_model()
me = customers.objects.get(name='Josh Smeaton')
me.address = 'Over the rainbow'

This assumes 6 that you have legacy tables with the same 5 structure. Instead of creating a model to 4 wrap each of the tables, you define one 3 base model, and dynamically construct the 2 class needed to interact with a specific 1 table.

Score: 1

Use isapi-wsgi and django-pyodbc to run Django on Windows using 1 IIS and SQL Server!

Score: 1

Use asynchronous tasks. Use Celery


Score: 1

Read Unbreaking Django if you haven't already. It contains 2 lots of useful information regarding django 1 pitfalls.

Score: 1

A bit late to the party. But Django Canvas 13 has recently come out and it deserves a 12 place here.

Don't start your project with 11 django-admin.py startproject. Instead you can use something like Django Canvas to 10 help piece together a blank project with 9 the modules you need.

You go to that site, tick 8 some options and then download a blank project, so 7 simple.

It has all the common things like 6 South schema migrations and Command Extensions 5 as well as a lot of other best practices 4 mentioned here. Plus it has a great start.sh/shart.bat script 3 that will install python, virtualenv, pip, django 2 and whatever you need to start from a fresh 1 copy of windows, osx or linux.

Score: 0

When passing variables from a view to a 8 template the response dictionary can become 7 tedious to type out. I find it nice to just 6 pass all the local variables at once using 5 locals() .

def show_thing(request, thing_id):
    thing = Thing.objects.get(pk=thing_id)
    return render_to_response('templates/things/show.html', locals())

(Not a hidden feature per se but nevertheless 4 helpful when new to Python and or Django.)

Edit: Obviously 3 it's better to be explicit than implicit 2 but this approach can be helpful during 1 development.

Score: 0

dir() & raise ValueError()

For debugging / exploring the state of things 8 during development, I use the following 7 trick:

  to_see = dir(inspect_this_thing)
  to_see2 = inspect_this_thing.some_attribute
  raise ValueError("Debugging")

This is especially helpful when you're 6 working on parts of django that aren't particularly 5 well documented (form.changed_fields is 4 one I used this on recently).


Instead of 3 writing out every variable for the template 2 context, use the python builtin locals() command 1 which creates a dictionary for you:

#This is tedious and not very DRY
return render_to_response('template.html', {"var1": var1, "var2":var2}, context_instance=RequestContext(request))

#95% of the time this works perfectly
return render_to_response('template.html', locals(), context_instance=RequestContext(request))

#The other 4.99%
render_dict = locals()
render_dict['also_needs'] = "this value"
return render_to_response('template.html', render_dict, context_instance=RequestContext(request))
Score: 0

Django hasn't got app settings, so i made 16 my own app_settings.py detection. At the 15 bottom of the settings.py i added this code:

import sys, os
# Append application settings without triggering the __init__.
for installed_app in INSTALLED_APPS:
    # Ignore django applications
    if not installed_app.startswith('django.'):
        # Find the app (and the settings file)
        for path in sys.path:
            path = os.path.join(path, installed_app, 'app_settings.py')
            if os.path.isfile(path):
                # Application settings found
                exec open(path).read()

It 14 detects app_settings.py in all the INSTALLED_APPS. Instead 13 of importing it, it will read the contents 12 of the app_settings file and will execute 11 it inline. If app_settings is imported directly 10 all sort of Django import errors will be 9 raised (because Django isn't initialized 8 yet).

So my app/app_settings.py will look 7 like this:


Now the application only has to 6 be added to the INSTALLED_APPS, instead 5 of finding all application settings and 4 add them to the settings.py (middleware, urls...)

Note: It 3 would be better if Django had a hook to 2 append extra settings, so application settings 1 could be added on startup (or in runtime).

More Related questions