alex gaynor's blago-blog

Posts tagged with reusable

DjangoCon 2010 Slides

Posted September 13th, 2010. Tagged with applications, reusable, django, open-source, djangocon.

DjangoCon 2010 was a total blast this year, and deserves a full recap, however for now I only have the time to post the slides from my talk on "Rethinking the Reusable Application Paradigm", the video has also been uploaded. Enjoy.

You can find the rest here. There are view comments.

Hey, could someone write this app for me

Posted June 8th, 2010. Tagged with applications, testing, python, fixtures, reusable, django.

While doing some work today I realized that generating fixtures in Django is way too much of a pain in the ass, and I suspect it's a pain in the ass for a lot of other people as well. I also came up with an API I'd kind of like to see for it, unfortunately I don't really have the time to write the whole thing, however I'm hoping someone else does.

The key problem with writing fixtures is that you want to have a clean enviroment to generate them, and you need to be able to edit them in the future. In addition, I'd personally prefer to have my fixture generation specifically be imperative. I have an API I think I think solves all of these concerns.

Essentially, in every application you can have a fixture_gen.py file, which contains a bunch of functions that can generate fixtures:

from fixture_generator import fixture_generator

from my_app.models import Model1, Model2


@fixture_generator(Model1, Model2, requires=["my_app.other_dataset"])
def some_dataset():
    # Some objects get created here

@fixture_generator(Model1)
def other_dataset():
    # Some objects get created here

Basically you have a bunch of functions, each of which is responsible for creating some objects that will become a fixture. You then decorate them with a decorator that specifies what models need to be included in the fixture that results from them, and finally you can optionally specify dependencies (these are necessary because a dependency could use models which your fixture doesn't).

After you have these functions there's a management command which can be invoked to actually generate the fixtures:

$ ./manage.py generate_fixture my_app.some_dataset --format=json --indent=4

Which actually creates the clean database enviroment, handles the dependencies, calls the functions, and dumps the fixtures to stdout. Then you can redirect that stdout off to a file somewhere, for use in testing or whatever else people use fixtures for.

Hopefully someone else has this problem, and likes the API enough to build this. Failing that I'll try to make some time for it, but no promises when (aka if you want it you should probably build it).

You can find the rest here. There are view comments.

Towards Application Objects in Django

Posted March 28th, 2010. Tagged with applications, reusable, django, python.

Django's application paradigm (and the accompanying reusable application environment) have served it exceptionally well, however there are a few well known problems with it. Chief among these is pain in extendability (as exemplified by the User model), and abuse of GenericForeignKeys where a true ForeignKey would suffice (in the name of being generic), there are also smaller issues, such as wanting to install the same application multiple times, or having applications with the same "label" (in Django parlance this means the path.split(".")[-1]). Lately I've been thinking that the solution to these problems is a more holistic approach to application construction.

It's a little difficult to describe precisely what I'm thinking about, so I'll start with an example:

from django.contrib.auth import models as auth_models

class AuthApplication(Application):
    models = auth_models

    def login(self, request, template_name='registration/login.html'):
        pass

    # ... etc

And in settings.py:

from django.core import app

INSTALLED_APPS = [
    app("django.contrib.auth.AuthApplication", label="auth"),
]

The critical elements are that a) all models are referred to be the attribute on the class, so that they can be swapped out by a subclass, b) applications are now installed using an app object that wraps the app class, with a label (to allow multiple apps of the same name to be registered). But how does this allow swapping out the User model, from the perspective of people who are expecting to just be able to use django.contrib.auth.models.User for any purpose? Instead of explicit references to the model these could be replaced with: get_app("auth").models.User.

What about the issue of GenericForeignKeys? To solve these we'd really need something like C++'s templates, or Java's generics, but we'll settle for the next best thing, callables! Imagine a comment app where the models.py looked like:

from django.core import get_app
from django.db import models

def get_models(target_model):
    class Comment(models.Model):
        obj = models.ForeignKey(target_model)
        commenter = models.ForeignKey(get_app("auth").models.User)
        text = models.TextField()

    return [Comment]

Then instead of providing a module to be models on the application class this callable would be provided, and Django would know to call it with the appropriate model class based on either a class attribute (for subclasses) or a parameter from the app object (to allow for easily installing more than one of the comment app, for each object that should allow commenting), in practice I think allowing the same app to be installed multiple times would require some extra parameters to the get_models function, so that things like db_table can be adjusted appropriately.

I think this could be done in a backwards compatible manner, by having strings that are in INSTALLED_APPS automatically generate an app object that was the default "filler" one with just a models module, and the views ignoring self, and a default label. Like I said this is all just a set of ideas floating around my brain at this point, but hopefully by floating this design it'll get people thinking about big architecture ideas like this.

You can find the rest here. There are view comments.