Django App Design: Extend or Build From Scratch?

Django has proven itself (to me, anyway) as a great tool for the job of creating very robust web applications with lightning speed. In just a week or two, I’ve created a site that encompasses a blog with an akismet-powered comment moderation system, a code sharing section complete with highlighted code segments (and line numbers), and I have a way to create static HTML pages and map them to whatever URL I want. Behind all of this is an administrative area where I can add/edit/delete any type of content hosted on the site, add users, put them in groups, and even create new sites, and map content to the different sites. It’s pretty powerful.

One thing I really like about Django is that it lets you be sort of a commitment-phobe, and actually rewards you for it. If you’re not sure which direction you want to go in with a given feature, just make it as generic as possible. Not sure which URL you want some content to show up at? No problem — edit a line in the project’s URLConf, and it’s somewhere else now. Need to redo that sidebar menu to pull in content from a completely new app? No problem. Edit a template with a couple of new tags, delete some others, and if you’ve set up inheritance properly, that’s it. Done. Decided you want users to be logged in to see some content? Multiple ways to do that – edit the view, edit the template… easy, easy, easy.

And did I say powerful?

However, with great power, of course, comes great responsibility. One thing I don’t want to do is create some monstrosity of code with tightly-coupled entities, because that takes away my ability to be non-commital and make on-the-fly changes with the greatest of ease. As it turns out, being non-commital takes a bit of thought, and a bit of work.

So here’s the deal…

I have a blog app which I think is extremely similar to the blog app in Practical Django Projects, 2nd Edition. It has an Entry object which has some rather nice features that I think are generically useful regardless of whether this “Entry” happens to be a blog post, an article in a CMS, a code snippet, or whatever. And this is the root of my design dilemma.

I’d like to devote a section of my site to republished articles I’ve written over the years, and new ones I plan to write going forward. Having used Django’s built-in flatpages app for static HTML content, I can already see that it’s really not up to doing double-duty as a CMS. Specifically, it doesn’t have the notion of status, so I can’t mark something “Draft” and come back to it later. It also requires me to put in a URL to create a static mapping between a URL and a flatpage object. Also, flatpage objects don’t have attributes I’d like to have like “Original Publication Date”, “Original Publication URL”, “Last Updated”, etc. There’s no notion of categories, tags, or anything like that, either, which I think could be useful in presenting the list of available articles.

But my blog app has a good bit of that functionality, and my Entry object has a good number of the attributes I want. So where to from here?

Well, I haven’t looked deeply into this, but I know I could subclass Entry, make the one or two changes I’d need, and go that route. Unfortunately, doing this basically means that the CMS isn’t really “standalone”. It depends on my blog app.

The other option is to build the features I want *into* the blog app itself. I haven’t looked deeply into this either, but I don’t think it would be all that difficult to create a way for me to specify at the time I create an “Entry” that this piece of content is a “Blog Post” or an “Article”. However, at that point I’m basically turning my standalone blog app into something that is not just a blog app. If I ever built another site and only wanted a blog, I couldn’t just move my blog app into place and have it. Or… I could, but I’d have all this “Article” cruft hanging around in my admin interface.

This is all not to mention that I’d be breaking a tradition of keeping things small and simple, both to ease debugging, and to ease future development of the small, simple app. Everything becomes more complex. Maybe I’m answering my own question…

What to do?

I’m unsure which way to take it, to be honest. My thinking right now is that I’ll just copy my blog app’s models.py file to my new app, make my changes there in the new app, and ‘syncdb’. Sure, it’s redundant… but it’s only redundant *today*. If I decide later on to add a feature to the blog that makes absolutely no sense for the CMS (or vice versa), I win. If I decide to create a new site that only needs a CMS *or* a blog, I also win.

I’m always open to suggestions and bits of wisdom from folks who’ve been down this road before. If you see big gaping flaws in my logic, let me know. Otherwise, I’m gonna create some short-term redundancy in exchange for some long-term flexibility.

  • Nikos Delimpaltadakis

    I am trying to figure out the same problem exactly. Your approach is the best so far. For example base I have created a “news” application based on Practical Django Projects blog paradigm. If later I would like to create a news site focused to sports I think I would just create a “sport_news” application, taking the same “news” models, and adding to them some sport related fields.

  • http://pkarl.com Pete K

    I think I understand what you’re saying.

    Basically, you’ve created a generic model, and you’re wondering how you should organize yourself when it comes to re-using it.

    Is that it?

    Assuming it is, here’s what I’d do:

    Add in your generic models at the project level (/models.py), and extend them on a case-by-case basis within your apps (/app/models.py -> SpecificModel extends GenericModel)

    Like this: http://scottbarnham.com/blog/2008/08/21/extending-the-django-user-model-with-inheritance/ (but w/your own models instead of the included User model)

    Let me know if I’m way off, and I’ll re-read your post 4 or 5 times to get a better idea.

  • http://ionrock.org/blog/ Eric Larson

    One potential positive of keeping the systems integrated is that you can utilize one package. This can be helpful when you’re talking about deployments and fixing bugs since you only have one code base and you utilize configurations to enable/disable features. Likewise, if you see a good library you can break out of one of the apps, often times both will benefit.

    These arguments aside, I still think you’re on the right track. As soon as you move to a single code base you face questions of how generalized should the code be. Since Django (and most web frameworks for that matter) help you to make new applications quickly, creating a general solution doesn’t end up with the same returns since a new app is cheap.

    Generally, I think one huge benefit of a good framework is being able to start from scratch easily. Technology changes so quickly, it seems that software should also be nimble and frameworks helpful enough to capitalize on the newer techniques and ideas created by new tech.

  • Beetle B.

    I had the same problem.

    So I restarted (not a big deal – never got the first site online anyway).

    I created Entry as a standalone app. I then subclass it as needed. One such subclass goes into my blog app. Another goes into what I call an Article app (which, for now, is most things not blog related). Within the Entry app, everything is an abstract model, I think. I’ve created further subclasses within for items that take comments, etc.

    A bit cleaner.

  • m0j0

    @Beetle: That sounds reasonable, and sounds like the intended use case for subclassing. In my case, my site *is* live, and Entry is already being used, so I went the route of copying. In the end, I think it’s really “6 in one hand, half dozen in the other”.

    @Eric: odd, I figured bug fixing would be easier if I had standalone apps, because it immediately limits the scope of the bug, which means the damage is isolated, and you only have to trudge through that one app to find it, and the app is smaller. I agree with everything else you said, though, and thanks for the input.

    @Pete: putting things in the project instead of the apps couples the apps to the project, which means it’s harder to pick up an app and drop it into another project (which I expect to do). I think if you’re talking about starting from scratch where my base models will only be used when subclassed, that makes a little more sense, but then why not just create a new app for, say, my generic “Entry” like Beetle says?

  • Steve

    Why not inherit/extend FlatPage? Add a status, etc.

  • http://www.doughellmann.com/ Doug Hellmann

    It sounds like you’ve done the right thing from the perspective of your existing production installation. As you go along adding features, you may want to re-evaluate, but I see no problem with copying the code to make a new app. We’re too obsessed with code reuse, often to the point of making base classes too difficult to use because they try to be too flexible.

  • m0j0

    @Steve – I could do that, but flatpages is a pretty small bit of code that does very little. I use it for the “About” page right now, and I couldn’t see using it for much more. I’d be overriding bits, and there aren’t a whole lot of bits. It’s not like it’ll be a whole lot of work to surpass what flatpages does if I start from scratch (in fact, by the time you read this, my cms app already does more than flatpages does, and I only worked on it for about 2 hours).

    @Doug – thanks for your input on this.