📜 ⬆️ ⬇️

Automatic binding of URL to view

I recently hooked on Django and I really like this framework. However, there is a detail that is worrying. This is simultaneously editing the file with my views and the urls.py file when creating a new view. I understand that this is due to the fact that the URL and views of things are quite different and for greater modularity it is better to keep them separate, however for small projects it would be very convenient to be able to edit the view and its settings in one place.

Here I propose such a solution, of course, tied to the decorators.

So what ultimately do we want to get? Suppose we need to draw a new view. I would like to add the decorator with_url to this function:
')
@with_url(r'^my/cool/url/')
def my_cool_view(request):
...


so that he himself tied up everything, but we did not have to urls.py hands in urls.py

For this purpose, there is a small easyurls module from the package, let's call it, djangoutils :

urlpatterns = []

def with_url(url, context={}):
def decorator(fun):
global urlpatterns
urlpatterns.append((url, fun, context))

return fun

return decorator

def load_patterns(module_name):
from django.conf.urls.defaults import patterns
__import__(module_name)

return patterns(module_name, *urlpatterns)


What is he doing? The with_url decorator adds a URL binding to our view in the global variable urlpatterns . And the load_patterns function simply imports the views module so that all the decorators work, and then returns the completed urlpatterns .

It is used as follows. In the urls.py file we write

from djangoutils.easyurls import load_patterns

urlpatterns = load_patterns('app.views') + patterns(...)


where app.views is the views module of our application. We don’t look into this file anymore.

In the app.views module app.views import the decorator:

from djangoutils.easyurls import with_url


and now you can write new views like this:

#
@with_url(r'^json/list/items/')
@json_http
@in_list
def json_list_items(request, list):
...

# :-)
@with_url(r'^$')
@with_url(r'^start/', {'is_root': False})
def start(request, is_root=True):
...


Retreat: in general, I actively use decorators to facilitate writing the same type of code. For example, here the json_http decorator converts the result of a function into a JSON string and throws it in response.

The disadvantage of the proposed solution, which I see immediately, is the use of only one load_patterns in the URL. You can solve it by moving the urlpatterns from easyurls to the views module. I think this is easy to do, as an additional advantage will load_patterns need to use load_patterns and the standard include will be enough. As a drawback, you have to write out urlpatterns = [] in each views module, which we knit in this way. It may not be necessary if python from one module can create a global variable in another and check if it is already there.

This is not a bike, by the way?

Thanks to those who read to this point :-)

Source: https://habr.com/ru/post/24989/


All Articles