I've been using django for almost a year and I was always frustrated by its cumbersome urlpatterns system. While it is really flexible, it doesn't provide any shortcuts for widely-used url and views naming schemes.
Let me show in examples what I mean. As everyone, I started with the tutorial and worked with the following system: === urls.py === urlpatterns = patterns('', (r'^$', 'apps.app1.views.index'), (r'^news/$', 'apps.app1.views.news'), (r'^members/profile/$', 'apps.app1.views.members.profile'), (r'^members/secure/$', 'apps.app1.views.members.secure'), (r'^app2/page/$', 'apps.app2.views.page'), # some other app ... ) It becomes quite a large and hardy maintainable list when the number of applications and views grows. I do believe in DRY principle and I didn't like much that I had to repeat the URL bases and parent module names again and again. So I kept reading the docs and involved the system to the following: === urls.py === urlpatterns = patterns('', (r'^', include('apps.app1.urls')), (r'^app2', include('apps.app2.urls')), ) === apps/app1/urls/__init__.py === urlpatterns = patterns('apps.app1.views', (r'^index/$', 'index'), (r'^news/$', 'news'), (r'^members', include('apps.app1.urls.members'), ) === apps/app1/urls/members.py === urlpatterns = patterns('apps.app1.views.members', (r'^profile/$', 'profile'), (r'^secure/$', 'secure'), ) === apps/app1/views/__init__.py === def index(request): ... def news(request): ... === apps/app1/views/members.py === def profile(request): .... def secure(request): ... (I skipped app2.* files for easier reading) While this system had less redundancy and easier to maintain (the DRY benefits), it suffered from another DRY problem - there were two packages with the same structure (apps.app1.urls.* and apps.app1.views.*), with the highly related content. When I was renaming a view, I had to browse through two package structures and change the things twice. Still frustrating, you see. So what I decided, why do we have to keep urlpatterns apart of the views? Why wouldn't I put them in the same files? The architecture became: === urls.py === urlpatterns = patterns('', (r'^', include('apps.app1.views')), # note views, not urls (r'^app2', include('apps.app2.views')), ) === apps/app1/views/__init__.py === urlpatterns = patterns(__name__, # sic! (r'^index/$', 'index'), (r'^news/$', 'news'), (r'^members', include('apps.app1.views.members'), ) def index(request): ... def news(request): ... === apps/app1/views/members.py === urlpatterns = patterns(__name__, (r'^profile/$', 'profile'), (r'^secure/$', 'secure'), ) def profile(request): .... def secure(request): ... This was a good change. I had 50% less files, and I put the related info within the same modules. Also note the usage of __name__, which increased the DRY factor a bit more :-) Yet I wasn't fully satisfied. Whenever I renamed a view I had to patch the urlpatterns as well. I also remembered an old inconvenience I always felt with views modules. If I place views functions in a views module, and place like "normal" helper functions there as well, they got mixed. By looking at the code it is sometimes hard to understand which function is a view, and which function is a helper. So what I created is the @url decorator which solved the both problems: === urls.py === urlpatterns = patterns('', (r'^', include('apps.app1.views')), (r'^app2', include('apps.app2.views')), ) === apps/app1/views/__init__.py === @url(r'^index/$') def index(request): ... @url(r'^news/$') def news(request): ... urlpatterns += include_urlpatterns(r'^members', 'apps.app1.views.members') === apps/app1/views/members.py === @url(r'^profile/$) def profile(request): .... @url(r'^secure/$) def secure(request): ... @url(r'^path1/$', '^path2/$') # you can specify several patterns def multipath_view(request): ... def helper(): # easily distinguishable - no @url! ... Summarizing, the benefits are: - no more creating and supporting urlpattern maps (less files, less code, more DRY) - have the url associated with a view in-place - easily see if a function is a view - fully compatible with other chained decorators Implementation problems, or possible improvements: - it is hackish - the speed isn't constant time, it is O(N) where N is the number of currently loaded modules - I would like to make it support the no-arguments syntax: @url() def profile(request): .... and have the decorator automatically pull the function name as the url pattern, but that doesn't seem possible if there are further decorators (like @user_passes_test or @render_to) The source code can be found at http://www.djangosnippets.org/snippets/395/ --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/django-users?hl=en -~----------~----~----~----~------~----~------~--~---