Posted on May 17, 2008 at 2:24 A.M.

Django now supports Model Inheritance, and one of the coolest new opportunities that model inheritance brings is the possibility of the creation of mixins, so in this post I'll walk through the steps I went through to create some simple examples. This is just an excercise (although it could be modified to be more robust)--and right now there are better ways to achieve all of the effects of the following mixins. (See django-mptt, for example).

Model and Field Setup

First let's just set up two basic models. The first will be our mixin, NaiveHierarchy, which has a single field, parent, which is a reference to itself. Using this, we can traverse the tree and find all sorts of fun hierarchical information. Also, we'll create the canonical example model: the blog post. Our models start out looking something like this:

from django.db import models

class NaiveHierarchy(models.Model):
    parent = models.ForeignKey('self', null=True)

    class Meta:
        abstract = True

class BlogPost(NaiveHierarchy):
    title = models.CharField(max_length = 128)
    body = models.TextField()

    def __unicode__(self):
        return self.title

Now let's test to make sure that worked. We'll create some data and test that parent exists on the instances.

>>> from mixins.models import BlogPost
>>> bp = BlogPost.objects.create(title="post1", body="First post!")
>>> bp2 = BlogPost.objects.create(title="post2", body="Second post!", parent=bp)
>>> bp3 = BlogPost.objects.create(title="post3", body="Third post!", parent=bp2)
>>> bp.parent
>>> bp2.parent
<BlogPost: post1>

Inherited Class-Level Methods

So as you can see, everything is working correctly! But that really doesn't save us much time yet, as it's fairly easy to copy and paste fields onto new models, and we still have to write methods which take advantage of those new fields. In this case, I already know that I'm going to want to get the related children and descendants of my blogposts. So why not write those methods on the abstract model? Thanks to inheritance, those methods will apply to the new model as well.

class NaiveHierarchy(models.Model):
    parent = models.ForeignKey('self', null=True)

    def get_children(self):
        return self._default_manager.filter(parent=self)

    def get_descendants(self):
        descs = set(self.get_children())
        for node in list(descs):
            descs.update(node.get_descendants())
        return descs

    class Meta:
        abstract = True

Now, getting all the children or descendents of a particular node is easy:

>>> bp.get_children()
[<BlogPost: post2>]
>>> bp.get_descendants()
set([<BlogPost: post2>, <BlogPost: post3>])

Now this NaiveHierarchy mixin is starting to become quite useful! But what happens if I want to get all of the BlogPosts that have no parents? It's really manager-level functionality. So let's write a manager which defines a get_roots function. Unfortunately, using abstract managers doesn't quite work yet (it works for non-abstract inheritance), but it probably will in future versions of Django. In fact, by applying the latest patch on either Django ticket 7252 or 7154, it will work today. Let's see how this would look:

class NaiveHierarchyManager(models.Manager):
    def get_roots(self):
        return self.get_query_set().filter(parent__isnull=True)

class NaiveHierarchy(models.Model):
    parent = models.ForeignKey('self', null=True)

    tree = NaiveHierarchyManager()

    def get_children(self):
        return self._default_manager.filter(parent=self)

    def get_descendants(self):
        descs = set(self.get_children())
        for node in list(descs):
            descs.update(node.get_descendants())
        return descs

    class Meta:
        abstract = True

class BlogPost(NaiveHierarchy):
    title = models.CharField(max_length = 128)
    body = models.TextField()

    objects = models.Manager()

    def __unicode__(self):
        return self.title

Note that we needed to explicitly define objects as the basic manager, because once a parent class specifies a manager, it gets set as the default manager on all inherited subclasses. This would play out exactly how you would expect:

>>> BlogPost.tree.get_roots()
[<BlogPost: post1>]
>>> BlogPost.tree.all()
[<BlogPost: post1>, <BlogPost: post2>, <BlogPost: post3>]

Advanced Stuff

So now I really wanted to push the limit, and write a mixin which would enhance one of the basic methods of all Model classes: save(). This would be a DateMixin which would contain date_added and date_modified, where date_modified was updated on each save. To my surprise, this Just Worked. Let's see the final result:

import datetime
from django.db import models

class DateMixin(models.Model):
    date_added = models.DateTimeField(default=datetime.datetime.now)
    date_modified = models.DateTimeField()

    def save(self):
        self.date_modified = datetime.datetime.now()
        super(DateMixin, self).save()

class NaiveHierarchyManager(models.Manager):
    def get_roots(self):
        return self.get_query_set().filter(parent__isnull=True)

class NaiveHierarchy(models.Model):
    parent = models.ForeignKey('self', null=True)

    tree = NaiveHierarchyManager()

    def get_children(self):
        return self._default_manager.filter(parent=self)

    def get_descendants(self):
        descs = set(self.get_children())
        for node in list(descs):
            descs.update(node.get_descendants())
        return descs

    class Meta:
        abstract = True

class BlogPost(NaiveHierarchy, DateMixin):
    title = models.CharField(max_length = 128)
    body = models.TextField()

    objects = models.Manager()

    def __unicode__(self):
        return self.title

Conclusions

Mixins can be powerful tools, but there are some hazards in using mixins, which all boil down to the same basic problem: unexpected consequences. In the case of the DateMixin, if any other class has defined a save() method, our custom save() method simply won't be called unless called explicitly. Perhaps this is a documentation problem, but perhaps it's a fault in the idea of a date mixin altogether.

So all that being said, I'm not suggesting to go off and start using any of the mixins that I have provided here, but rather to illustrate how a mixin can be constructed with Django's new Model Inheritance. I do hope that a reusable app emerges with some great mixins that are useful for a large variety of tasks. Because mixins are powerful, and new shiny things that Django can do, and new shiny things are worth being explored!


Posted on May 4, 2008 at 6:12 P.M.

Lately there's been a lot of discussion in certain programming communities about which method of object extension makes more sense: inheritance, or composition. Most of the time these discussions turn into debates, and when that happens developers tend to "take sides"--often moving towards extremist positions on the issue. I've been sort of quietly thinking about it all lately, trying to determine which use case warrants which approach. Here I show examples of both, explore some properties and consequences of both composition and inheritance, and finally talk about my own preferences.

Examples of Composition and Inheritance

Before talking about the consequences of inheritance vs. composition, some simple examples of both are needed. Here's a simplistic example of object composition (using Python, of course, as our demonstration language):

class UserDetails(object):
    email = "floguy@gmail.com"
    homepage = "http://www.eflorenzano.com"

class User(object):
    first_name = "Eric"
    last_name = "Florenzano"
    details = UserDetails()

Obviously these are not very useful classes, but the essential point is that we have created a namespace for each User object, "details", which contains the extra information about that particular user.

An example of the same objects, modified to use object inheritance might look as follows:

class User(object):
    first_name = "Eric"
    last_name = "Florenzano"

class UserDetails(User):
    email = "floguy@gmail.com"
    homepage = "http://www.eflorenzano.com"

Now we have a flat namespace, which contains all of the attributes from both of the objects. In the case of any collisions, Python will take the attribute from UserDetails.

Consequences

From a pure programming language complexity standpoint, object composition is the simpler of the two methods. In fact, the word "object" may not even apply here, as it's possible to achieve this type of composition using structs in C, which are clearly not objects in the sense that we think of them today.

Another immediate thing to notice is that with composition, there's no possibility of namespace clashes. There's no need to determine which attribute should "win", between the object and the composed object, as each attribute remains readily available.

The composed object, more often than not, has no knowledge about its containing class, so it can completely encapsulate its particular functionality. This also means that it cannot make any assumptions about its containing class, and the entire scheme can be considered less brittle. Change an attribute or method on User? That's fine, since UserDetails doesn't know or care about User at all.

That being said, object inheritance is arguably more straightforward. After all, an e-mail address isn't a logical property of some real-world object called a "UserDetails". No--it's a property of a user--so it makes more sense to make it an attribute on our virtual equivalent, the User class.

Object inheritance is also a more commonly-understood idea. Asking a typical developer about object composition will most likely result in some mumbling and deflection, whereas the same question about object inheritance will probably reveal a whole host of opinions and experience. That's not to say that composition is some sort of dark art, but simply that it's less commonly talked about in so many words.

As more of a sidenote than anything else, inheritance can be speedier in some compiled languages due to some compile-time optimizations vs. the dynamic lookup that composition requires. Of course, in Java you can't escape the dynamic method lookup, and in Python it's all a moot point.

My Preferences

In general, I find object composition to be desirable. I've seen too many projects get incredibly (and unnecessarily) confusing due to complicated inheritance hierarchies. However, there are some cases where inheritance simply makes more sense logically and programmatically. These are typically the cases where an object has been broken into so many subcomponents that it doesn't make sense any more as an object itself.

The Django web framework has an interesting way of dealing with model inheritance, and I think that more projects should follow its example. It uses composition behind the scenes, and then flattens the namespace according to typical inheritance rules. However, that composition still exists under the covers, so that that method may be used instead.

The answer is not going to be "composition always" or "inheritance always" or even any combination of the two, "always". Each has its own drawbacks and advantages and those should be considered before choosing an approach. More research needs to be done on the hybrid approaches, as well, because things like what Django is doing will provide more answers to more people than traditional approaches. Cheers to continued thought about these problems and to challenging conventional thought!



Posted on Feb. 9, 2008 at 1:06 A.M.

Being a senior in college means many things. It means job interviews and upper-level classes, emotional instability and independent living. It also means countless hours of sitting in uninteresting classes whose sole purpose is to fulfill some graduation requirement. For me, that means lots of daydreaming--about anything other than that class. Recently however, during one daydream, I had a brain wave worth typing up: What's the deal with Object-Oriented Programming and Django?

The Convention

Browsing through the views.py file in just about any publicly-available Django-based application will almost certainly reveal nothing more than a bunch of functions. These functions are undeniably specialized: they take in an HttpRequest object (plus possibly some more information), and they return an HttpResponse object. Although these functions may be specialized, nevertheless they are still just functions.

This should come as no surprise to anyone who has used the framework--in fact, it's encouraged by common convention! Not only does the tutorial use plain functions for views, but also the Django Book, and just about every other application out there. The question now becomes "why"? Why, in a language that seems to be "objects all the way down", does a paradigm emerge for this domain (Django views) wherein functions are used almost exclusively in lieu of objects?

That's not entirely true, sir...

Any time a broad statement like "just about any" is used, the exceptions are what become interesting. The admin application (both newforms-admin and old) is probably the most notable and interesting exception to my earlier broad statement. It's interesting because it's Django's shining star! Other applications which use object orientation: databrowse and formtools. These are some great Django apps which use Object-Orientation in the views.

Looking at those apps which use OOP and those which don't reveals an interesting idea: those apps which strive to go above-and-beyond in terms of modularity tend to be those who end up using classes and their methods for views. Now this same functionality could be accomplished by using plain functions, but they haven't--their functionality was accomplished using classes and methods.

Please keep in mind that what I'm not trying to do is make a value judgement on Object-Oriented programming vs. functional programming vs. any other programming paradigm. Instead, I'm providing an observation about the emergence of a common practice, and trying to analyze its implications.

But wait!

What really is the difference between writing a plain function as a view and Object-Oriented programming? It's completely reasonable to argue that writing a plain function for a view is, in fact, Object-Oriented programming. All class methods take in self as their first positional argument, and all views take in request as their first positional argument. Taking in this argument allows access to state which would otherwise be difficult to access. Changing the order of urlpatterns is equivalent to changing the polymorphic properties of a class and dynamic method lookup.

In essence, one could argue that using a plain function as a view is strictly equivalent to writing a method on the HttpRequest object. Thinking about it in this way, writing a Django application is really nothing more than building up a monolithic HttpRequest object which the user can call different methods on using its API: the URL. To me, this is a really interesting idea!

Off My Rocker

This is the result of extreme classroom boredom--so maybe posts here will continue down this slightly-more-esoteric road for a while. But honestly this was an interesting thought-experiment, and I'd like to get some feedback on what people think as well. Am I totally off base with this analysis? Moreover, do you use true Python "classes" as your views? If so, what benefits does it bring to the table?

Search

 

Recent Links

  • git-issues: A distributed issue tracker built-in to Git.
  • I predicted this back in March--can't believe a solution has surfaced so soon. It makes so much sense to build in an issue tracker to a revision control system. Since you're working with the code, might as well track the issues in the same system and take advantage of the extra metadata. This is really cool (and as a bonus, it's written in Python) so I hope to see it really grow and flourish!

  • How I Work Daily
  • Daily blog by Kevin Fricovsky. In addition to having some really great content, he has started to post audio interviews with people from the Django community. This is a site to keep an eye on in the coming days and months.

  • django-arcade
  • Demo site for django-arcade, an open source reusable Django app to add new flash games to any django-powered site. Looks very cool for easily creating game portals. It also comes from my future employer.

  • Facebook Chat and Scalability (with Erlang)
  • Eugene Letuchy talks about how they they took Facebook Chat from no users to 70 million users, with the help of Erlang.

  • Simon Willison: The Implications of OpenID
  • I somehow missed this presentation when it came out, but it's an absolutely fantastic overview and defense of OpenID by Simon Willison. If you are in any way interested in what OpenID is and what it can offer, you owe it to yourself to check out this presentation.

  • StupidXML
  • Probably the simplest XML library that I've seen for Python. Sometimes you just want to generate some stupid XML, and this is the perfect tool for the job.

  • See the rest of my links...

Pownce

Badges

  • django badge
  • apache badge
  • GeoURL
  • XFN Friendly
  • Valid HTML 4.01 Transitional