Adding more CoC to Django

611 views Asked by At

I come from a Cake background, and I'm just starting to learn Django now. I'm liking it quite a bit, but I kinda wish it used convention over configuration like cake does. So,

  1. How can I get Cake-style URLs automatically? For example, if I went to mysite.com/posts/view/5 it would load up mysite.posts.views.view and pass an argument 5 to it? I was thinking I could add something like (r'^(.*)/(.*)', 'mysite.$1.$2'), to urls.py, but of course, that won't work.

  2. How can I automatically load up a template? Each view function should automatically load a template like templates/posts/view.html.

Is this even possible, or do I have to hack the core of Django?


Here's my solution, based on what Carl suggested:

urlpatterns = patterns('',
    # url pats here
    url(r'^(?P<app>\w+)/(?P<view>\w+)/(?P<args>.*)$', 'urls.dispatch')
)

def dispatch(req, app, view, args): # FIXME: ignores decorators on view func!
    func = get_callable(app+'.views.'+view)
    if args:
        ret = func(req, *args.split('/'))
    else:
        ret = func(req)
    if type(ret) is dict:
        return render_to_response(app+'/'+view+'.html', ret)
    else:
        return ret

Seems to be working pretty well with initial tests. Solves both problems with a single function. Probably won't support GET-style arguments tho.

2

There are 2 answers

4
Carl Meyer On BEST ANSWER

Those points are both implementable without hacking Django core, but either one will require a non-trivial level of familiarity with advanced Python techniques.

You can do the generic URL pattern with a pattern like this:

url(r'^(?P<appname>\w+)/(?P<viewfunc>\w+)/(?P<args>.*)$', 'myresolverfunc')

Then define a 'myresolverfunc' "view" function that takes "appname", "viewfunc", and "args" parameters, and implement whatever logic you want, splitting args on "/" and dynamically importing and dispatching to whatever view function is referenced. The trickiest part is the dynamic import, you can search Django's source for "importlib" to see how dynamic imports are done internally various places.

The automatic template loader can be implemented as a view function decorator similar to the various "render_to" decorators out there, except you'll generate the template name rather than passing it in to the decorator. You'll have to introspect the function object to get its name. Getting the app name will be trickier; you'll probably just want to hardcode it as a module-level global in each views.py file, or else work in conjunction with the above URL dispatcher, and have it annotate the request object with the app name or some such.

2
Zack The Human On

I don't you'll need to hack the core of Django for this. It sounds like you might be in need of generic views. Also check out the Generic Views topic guide.

The first example given in the generic views documentation sounds like your first bullet point:

Example:

Given the following URL patterns:

urlpatterns = patterns('django.views.generic.simple',
    (r'^foo/$',             'direct_to_template', {'template':'foo_index.html'}),
    (r'^foo/(?P<id>\d+)/$', 'direct_to_template', {'template':'foo_detail.html'}),
)

... a request to /foo/ would render the template foo_index.html, and a request to /foo/15/ would render the foo_detail.html with a context variable {{ params.id }} that is set to 15.