Posts Tagged ‘reusable’

My Idea Of The Django Blogging App™

Wednesday, April 28th, 2010

I am not going to talk about yet another Django-based blogging engine in this post. There are a number of blogging apps which try to be like turn-key solutions, like a WordPress blog. I have skimmed through the code of many such apps, but haven’t used one yet. Some of them are really high quality apps. What I have in mind is somewhat different though. I would like an app that would allow me to build a blog that satisfies my projects specific requirements.

Let me reiterate the last sentence. Having a Django-based blog just because Django is fashinable is a little dumb in my opinion. If Django-based X blogging engine suits you better than anything else, use it. Why not? But my personal choice of blogging engine is WordPress1. The value of a Django blogging app, for me, is in adding a blog to a Django project. And different projects might have different requirements. So my idea of a Django blogging app is one that is highly configurable and highly extendable.

On the other hand I don’t need the convenience of clicking a checkbox on a polished UI. I can write a function. Or I don’t necessarily need it to, say, provide a navigation menu. There are apps that do that. Even if there wasn’t it shouldn’t be the blog app’s job. So I am not looking for an instant-blog. I have a Django app in my mind, nothing more.

What Should Be Left Out

Basically any feature that can be provided by another reusable app should be left out. Why should we re-implement something that is already done… and reviewed by others… and tested. Of course this doesn’t necessarily mean providing no convenience functions.

  • No admin. Because we already have one.
  • No theming. For the love of Flying Spaghetti Monster, you don’t need any theming other than what django.template offers. Pre-built themes are for turn-key solutions.
  • No comments or contact forms. (See django.contrib.comments and django-contact-form)
  • No official markup format (or formats). This can be handled in the templates without difficulty. But, maybe, pluggable content filters is a good idea. I haven’t made up my mind on this one entirely. It won’t use any markup format by default, that is for sure.

What Should Be Included

Remember, every project has a different set of needed features for its blog. Some need catagories, some need tags and some others need both. But it would end up as a disaster if we implemented each one of those features into a single app. Instead I think it should consist of many small apps that work together. But I wouldn’t want to end up having huge spaghetti of apps that all depend on one another, like Pinax does. A minimal amount of core apps2 and then everything else should be optional. By optional I mean you don’t have to install packages you won’t need.

I think the components (apps) should be activated via adding to INSTALLED_APPS and configured with settings. I can’t think of any parameter that needs to be changed dynamically, so why not use the established way of doing configuration in Django.

Two must have features for such a blogging app are previews and scheduled publishing. It is possible that you sometimes write a post quickly and publish it immediately. But I suppose nobody will say they don’t care about these two features.

Built-in feeds and sitemaps are also nice to have.

Multiple instances of this blogging app running on the same project? À la admin. I can’t make my mind on this one. Sure it would be a nice feature. But it could complicate the code. Peehaps too much for a not so common case.

What do you think about the general idea? Are there any other must-have features? Would you be willing to learn a new app when you are already comfortable with another blogging app?


1: Even though it’s written in the abomination called PHP. But since there are plugins for everything I don’t have to touch the code.

2: One sounds like a good number, if possible.

Bookmark and Share

Developing Reusable Django Apps: Signals

Thursday, March 4th, 2010

I wrote “signals provide a great way to propagate the events generated from your app” earlier. I think reusable apps should avoid hardcoding any kind of event handling and send signals instead. App consumers might prefer an email over an on-screen notification. They may even choose to ignore the event silently. A reusable app should give this choice to the consumer.

Taking advantage of signals doesn’t necessarily mean providing no sane defaults. You can send signals and provide default event handling. Here is a couple of ideas how this can be done:

  • Your app can check if there are any listeners and connect the default handlers if there is none.
  • You can ship an auxiliary app that connects default handlers when added to INSTALLED_APPS.

I personally prefer the second approach since it’s simpler and more explicit. I’m sure there are other ways to implement default handlers for signals.

Dispatch_uid

Don’t forget to assign a unique dispatch_uid for each connect() call. Otherwise your handler can get connected twice. I would also suggest you to use both module path and your handler function’s name in your dispatch_uid:

"%s.%s" % (os.path.splitext(__file__)[0].replace(os.sep, '.')[1:],
           handler_name)

Now I should take my own advice and replace hardcoded User.message_set.create()s with signals in django-simple-friends.

Bookmark and Share

Developing Reusable Django Apps: App Settings

Tuesday, January 26th, 2010

Eventually your app will need some sort of configuration. Supplying many parameters to customise your views, template tags and filters to allow template authors easily harness the power of your app and implementing registration pattern are all sensible things to do. But at some point you will need configuration for your app at project level. Because app level configuration is stupidnot reusable. Consumers of your app should never have to change its source code. And what better place to put our configuration statements than settings.py? Remember; we want to make things easier for our app’s consumers, not harder. There is no need to add a new file to the project for a few lines of settings1.

We already know we shouldn’t import settings.py directly. Instead we import the settings object (much like a singleton) of django.conf module:

from django.conf import settings

Now you can access different configuration options as attributes on this object. But I suggest you to use getattr() in order to avoid getting AttributeErrors. Also, notice how we didn’t hardcode the name of the attribute in the second method below:

# This is too verbose
try:
    some_setting = settings.SOME_SETTING
except AttributeError:
    some_setting = DEFAULT_VALUE

# Plain and simple
some_setting = getattr(settings, 'SOME_SETTING', DEFAULT_VALUE)

Instead of requiring consumers to define all your app settings it is better to supply sensible defaults. Also I find it useful to prefix names of app settings within settings.py.

# in settings.py
MYAPP_FOO_CHOICES = [('bar', u'Bar'), ('baz', u'Baz')]


# in myapp/models.py
from django.db import models
from django.conf import settings


FOO_CHOICES = getattr(settings, 'MYAPP_FOO_CHOICES', [('quux', u'Quux')])


class FooRecord(models.Model):
    foo = models.CharField(max_length=10, choices=FOO_CHOICES)

This works fine for simple apps with fewer settings. But it can easily get out of hand when your app grows. An app_settings.py module would help keeping track of configuration by keeping all configuration options in one place:

# in myapp/app_settings.py
from django.conf import settings


FOO_CHOICES = getattr(settings, 'MYAPP_FOO_CHOICES', [('quux', u'Quux')])


# in myapp/models.py
from django.db import models
from app_settings import FOO_CHOICES


class FooRecord(models.Model):
    foo = models.CharField(max_length=10, choices=FOO_CHOICES)

To summarize the points above:

  • Import settings from django.conf
  • Use getattr()
  • Always supply a default value.
  • Prefix settings you made up in settings.py
  • Use app_settings.py if you have many

1: If your configuration is long, say more than 100 lines, you should step back and reconsider. Perhaps you should prefer a strategy similar to django.contrib.sitemaps or django.contrib.syndication.

Bookmark and Share

Developing Reusable Django Apps

Wednesday, January 13th, 2010

Django app structure is an implementation of seperation of concerns. It is slightly different than what you can find in other MVC frameworks. The stack is split vertically, not horizontally. And then the app is split horizontally within, i.e. models, views, templates etc are in their seperate modules/packages/directories. This vertical splitting allows you to collect all ingredients of one functionality in your project in one place.

Framework Structure

I think apps1 are one of the strong points of Django. A selling point if you like. There is a great ecosystem of apps, you can find an app for almost anything posssible with Python. And Python is kick-ass when it comes to library wealth. But there is another major advantage of apps when they’re done right; a sane code base. Here is a slide from the Django in the Real World presentation by Jacob Kaplan-Moss:

The fivefold path

  • Do one thing, and do it well.
  • Don’t be afraid of multiple apps.
  • Write for flexibility.
  • Build to distribute.
  • Extend carefully.

I will focus on flexibility and interoperability of apps in this post. But before we proceed I would like to emphasize the first bullet point in the slide. Because the scope of your app plays a big role in its flexibility and interoperability. Apps should be small enough to easily understand and integrate (into a project). Many times I have moved away from an otherwise good app because of its many dependencies and/or excessive features. On the other hand apps should be big enough to allow for different configurations and allow extension without modifying their code. Do one thing, and do it well.

Scope of an app

Take django-tagging for example; it’s 1.3 KLOC but it does tagging and nothing else. There are no dependencies other than Django, you can add tags to any model without modifying the model source, a tag can be associated with any type of model and tagging hides the gory details from you… In short; finding the right size is important. This is why tagging is the tagging app for Django.

Building For Reuse

General advice is “even project specific apps should be reusable“. Slapping the same app onto another project is not the only advantage. In fact it may not be possible if you are not in the habit of upgrading your whole project to recent versions of Django. The main advantage as I have said before is sanity. I prefer Django to other web frameworks/environments because it provides a civilized way of development. Let’s accept it; web programming is not a particularly interesting, exciting or intellectually rewarding field. You write the same piece of code over and over. And worst of all the challanges you face are actually a result of either the underlying system was designed by morons or you are trying to use it for something it’s not intended to be used. So it is only natural that web programmers feel they’re rusting. Django eases the pain. If you stick to certain conventions serenity will follow as well.

Naturally the framework does most of the work regarding app flexibility and interoperability. Take URLs for instance include('myapp.urls') and you are good to go. You don’t have to bind views one by one. Is it inflexible? Who said urls.py can only contain a hardcoded list of URLs. You can do anything that is possible with Python. You can generate different urlpatterns based on a setting for instance.

It is relatively easy and straightforward to reuse and extend forms and views (both function based and class based). Models are a little harder to get right though. You should always think of the most difficult situation which is you can’t touch either app’s code. Registration pattern of admin app provides a good solution here. You can register a third party model to another third party app in just a few lines.

You don’t need to write lots of code to get the flexibility and interoperability. Well designed apps make good use of settings.py for example. Why should the project developer wrap a view when a single line assignment would do the job? Supplying good templatetags and template snipplets (includes) is another way to make things easy for app consumers.

Signals provide a great way to propagate the events generated from your app. Even though they are one way2, signals are extremely powerful. Any number of observers can connect to a signal and you can send a signal anywhere in your code. Literally. It is even possible your app suppying a signal and then another app sending it3.

There are many more ways to tame your app to be reusable. It all starts with your determination and discipline. Just like documentation, testing and maintaining a software generally. I will write more about reusable apps.


1: The word application is used both for a web application and a Django application. To avoid confusion I always use app to indicate the latter.

2: Signals don’t have return values. But you can use a callback AFAIK.

3: I can’t think of an example this would be useful, but still…

Bookmark and Share

Django: Where Should My App Live

Thursday, March 12th, 2009

Python is my preferred language and Django is my preferred environment for web applications. Django’s probably the most important strength is how it splits different parts of an application and allows (and encourages) decoupling between them. This way you get to have many small re-usable and, if designed well, highly configurable apps (in Django terms).

The frameworks itself comes with a set of apps, contrib apps. These are officially supported applications for most general tasks. For example Django has a syndication app that allows you to create feeds for your content easily, a comments app for.. well comments, a redirects app for dynamically managing URL redirects. And let’s not forget the renowned admin app.

Third party re-usable apps can be used to complement contrib apps. These apps provide more specific funtionality, such as providing a dynamically generated robots.txt. Third party apps usually have no dependencies other than Django (and therefore contrib apps). Best third party apps are the ones that provide just enough functionality on one task. It’s the similarity with UNIX philosophy that makes Django apps so attractive; do one thing, do it well.

Finally there is your project specific code. Although it is not a must, I think it is a good design pattern to put project specific code in one or more project specific apps. These apps will probably have lots of dependencies to other apps, but that is cool. These apps will only function as glue between re-usable apps.

Django Default

How does django-admin (or manage.py within your project) handle apps? “manage.py startapp appname” command creates a new app inside your project directory with the following file structure:

appname/
    __init__.py
    models.py
    views.py

And then, assuming your project directory name is myproject, you can import your models like “from myproject.appname.models import Foo“. Two things to note here:

  • Your new app is inside your project directory. This is normal, but significant at the same time. More on this later.
  • Your code is coupled with the project directory’s name. You might be fine with it in the beginning, but at some point you should realize that the project you are working on is not a library, it is an application. Therefore it ought to be independent of the containing folder name. But the real problem is that your app is coupled with the project, tightly.

The first point is not an obstacle until you decide to distribute your app individually. An app is just a library, it can live anywhere inside your PYTHONPATH. In other words; as long as you can import it, location of your app is irrelevant.

The second point is important. If you plan to re-use your apps, you need to:

  1. Make sure you have cleaned up all project specific code.
  2. Minimize dependencies to other apps, especially non-contrib apps.

Adding Project Directory To PYTHONPATH

A quick fix could be to add the project directory to PYTHONPATH. This makes all libraries within accessible from python.

You don’t need to modify PYTHONPATH for development server. But for both development and production environments you will need to modify your settings.py with the following:

import os

# Absolute path for the project directory
_PATH = os.path.abspath(os.path.dirname(__file__))

# Name of the project directory
_MODULE = os.path.basename(_PATH)


# Define absolute path for media
MEDIA_ROOT = _PATH + '/media/'

# Decouple project directory
ROOT_URLCONF = _MODULE + '.urls'

# Import apps within porject directory
# independent from its name
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    _MODULE + '.myapp',
    _MODULE + '.yourapp',
)

This only makes project directory an independent variable, adding a bit of flexibility. But your apps are still within the project directory and from a practical point of view; they are not yet ready to be shared between projects.

Seperating Apps From Projects

As I said above, and app is a library. If you can import it, it can live anywhere. I personally prefer putting all my re-usable apps in one directory and symlinking them somewhere within PYTHONPATH.

# Import apps directly
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'myapp',
    'yourapp',
)

Now if your app is decoupled in code level it should be re-usable since we have decoupled it from the project directory. This, however easy at the beginning, introduces a little more work in terms of maintenance. You need to deploy and maintain your re-usable apps and projects seperately.

Lifetime Of An App

I always do my best to model any app as re-usable. But to speed up my first few iterations I follow the plan below:

  1. First thing I do when I create a new project is to set up _MODULE & _PATH in my settings.py.
  2. Initially I allow my apps to be tightly coupled. Adding customizability and extensibility where it is easy.
  3. Once it functions the way I want, I start de-coupling. If it is truly project-specific code, I just spend minimal effort de-coupling. I don’t think this is a waste of time. It will probably pay off in the future as less maintenance cost.
  4. When the app has no minimal dependencies, I move it to my django apps dir. So far I have had the advantage of using the same (source control) repository with the project. But now the app is mature and it should live in its own repository.
Bookmark and Share