Ok here it goes: I don't have a proper platform for my observations /
rants so I figured I'd try my luck here. Django has been my favorite
framework for developing web applications for about a year and a half,
so it comes from a position of love when I say that the Django app
really sucks as a level of abstraction. And I'm really looking for a
way out so any suggestions are much appreciated. A tl;dr is provided
below.

Others have complained before me. Two particular ones worth mentioning
are:
http://www.scribd.com/doc/37113340/Why-Django-Sucks-and-How-we-Can-Fix-it
which claims that "Apps which provide models are inflexible" and
http://www.mutualinformation.org/2010/03/why-i-switched-to-pylons-after-using-django-for-six-months/
Both claim that the Django app provides the wrong level of
abstraction, neither goes in too much detail exactly why that is the
case. That's the question I'll attempt to answer.

Before we can answer the question we must first set some reasonable
expectations for an "app". I'd say an app is a small package of
closely related features as they are presented to the user (in the
context of a web project) that can be easily modified/extended for any
given project.

Examples of apps (in my own particular context):
* Dealing with customer information (a mini CRM). Adding, editing,
useful overviews.
* A small news app (Add, edit, overviews)
* Our own particular UserProfile app (editing, viewing others,
birthday calendars etc.)
* A small budgetting tool (creating budgets, see how much money has
been used)
* Logging time lines (for worked hours), searching them.

I choose this definition for "app" because it is a very useful one in
the context of web projects. At least in my context it works like
this: we have a lot of customers with similar intranets and extranets.
Each one of them might want a particular subset of the various apps we
have "on the shelf".

By the way: there's other things that can already be reused quite
well. Anything pure python for example. Or extensions to Django (extra
fields, extra context managers, middleware etc etc.) This is not my
concern, mainly because it already works well.

One thing that deserves extra stress is that apss should be easily
extendable. Exactly the fact that every customer want something that
is slightly different from the next is how we're able to provide
value. (This is also the reason I like Django in the first place:
making stuff "your own way" is very easy). So: if no one want exactly
the same, extensibility is a major prerequisite for reusability.

What are some typical things we want to do when extending (modifying)
an app for the context of a particular project?
* Deal with authorization in the context of the particular django
project
* Styling for the project
* Turn a subset of the functionality on or off for a given project (no
docs, no 'advanced features')
* Add one or more fields to one or more models and possibly related
edit pages, view pages forms etc

Given this control flow let's try to do some of the typical
modifications mentioned above:
Authorization:
Django has a beautiful mechanism for authorization, which is using
decorators (@may_do_a_b_or_c) directly in the views.py.
Tempting, but will not be modifyable in any way once you lift the app.
(because the decorator will become tied to the view function). Other
mechanisms are not presented (in a standardized way). If anyone has
ideas about this I'd love to discuss them.

Styling:
This actually works well, by providing sufficient amount of hooks in
the templates and extending.

Turning functionality on and off:
This could be made to work by working with a 'url_parts.py' in the
reusable app, that provides different url_patterns for the various
subsets. So one for the CRUD, one for the docs, one for the simple
features and one for the advanced features. Our project's urls.py
would then simply include the right subset from this url_parts.py. I'm
not sure it's very pretty though.

Extending models
This is the big one, for two reasons.
1. You almost always want to do this (for any change to the app that
is reflected in the underlying data)
2. It's pretty much impossible.

Why is it impossible?
Firstly, /app/models.py is always discovered, so unless we make all
Models abstract, or we do not include "app" in settings.py, models are
created for syncdb and any related commands.

Secondly, let's take a look at Django's control flow:
* urls.py matches and calls,
* possibly via a decorator
* a view in views.py, that may use any number of
  * models,
  * forms and
  * templates
The "official" way to modify a reusable app for your particular app is
by making it available as a kwarg with proper default in the view, and
then customizing it from urls.py.
However, if you simply want to add one field to a much used object,
this solution implies passing around the object class (factory)
through your whole app. That's not very elegant.
The same goes for any other changes at a lower level. Say I want to
swap in a particular Form (not uncommon). Or reuse 90% of the views
from an app, but replace 10% of the alltogether. If those 10% are
referenced from {% url %} tags (or reverse in a view) we're screwed.

By the way: where do modifications of apps go anyway? The reusable app
already goes into /appname. So the modification (presuming it warrants
a full directory) goes into /my_appname? If reusable apps are common,
this means my projects look like this:
/app_a
/app_b
/app_c
/my_app_a
/my_app_b
/my_app_c

Solutions:
http://www.scribd.com/doc/37113340/Why-Django-Sucks-and-How-we-Can-Fix-it
mentions using factories "everwhere". Too bad the actual speech cannot
be heard at scribd because the slides are just a bit thin on details.

settings.py
In my humble opinion a good app adds no settings to settings.py. The
problems with settings.py are mentioned in many places, suffice to say
it's basically a big global. Also: we're programmers, not configurars.

For the models problem specifically I came up with this about 7 months
ago:
https://bitbucket.org/vanschelven/superglue/ (very much proof of
concept)

Superglue works like this:
For any reusable app that uses it, models are to be defined abstract.
Then a magic method (glue) is to be called (from the apps models.py).
This magic method looks at settings.py (meh) and possibly extends the
model. At that point the extended, non-abstract model is made
available for the rest of the app.
I don't really like it yet, but it could be a start.

Another possible way forward could be object oriented views, like
here:
http://djangosnippets.org/snippets/1009/

tl;dr
* Django Apps Suck. Your reply explaining why they don't is expected.
* Reuse of a lot of things doesn't suck. But the specific unit app,
meaning a bunch of models that can be modified and presented with
their model-specific features, is extremely hard to reuse.
* Apps are mostly hard to reuse because they are hard to reuse with
minor modifications (extensions).
* Using decorators on views to define authorization levels ties in
said authorization levels with the app (and makes it non-reusable)
* The hardest things to change are at the bottom of Django's call
chain. Deep inside the views, we find particular Models, Forms and
references to other views.
* Models are extra hard to change, because they are expected to be non-
abstract in the app.
* There is no logical separation (dir structure) between "a reusable
app" and "my modifications to a reusable app".
* Settings.py is not a solution (it is a problem), though I don't
bother to explain why.
* Some ideas for solutions exist, but this seems to be an open problem
in the Django world.
Correct me if I'm wrong.

hope to hear from you,
Klaas van Schelven

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-us...@googlegroups.com.
To unsubscribe from this group, send email to 
django-users+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en.

Reply via email to