Latest Entries
Published on Dec. 8, 2009
It's been a month since the initial release of django-rbac and so far it turned out to be pretty useful for many people. I am therefore happy to have contributed another grain of sand to the open source Django community beach.
In Django, as in any MVC oriented framework, developers have to choose which side to put the logic on: a model method or function, inside a view or in a template tag. Although many recommend putting as little logic as possible in template tags, I know sometimes it is good to have one at hand to keep a healthy equilibrium, otherwise views can grow up fat or methods can spread like lemmings in your models and managers. I have recently added two template tags to django-rbac, to request for permission at model or object_level (RBACGenericPermission or RBACPermission, respectively).
For example, a template rendering a profile page for a user can decide whether or not to show some personal information at rendering time, using the if_rbac_permission tag:
{% if_rbac_permission owner model_inst operation roles %}
<p>Pau Casals, 45 years old, male</p>
{% else %}
<p>You cannot view this information</p>
{% endif_rbac_permission %}
I updated the app documentation, there you can find another example on using the template tags. Usage is similar to the manager methods, regarding to kind of arguments and order of them in the call, in order to keep consistency. I also improved a bit the example project, including a template to show how to use the template tags.
Hope you like it!
Published on Dec. 2, 2009
Last Monday the Spanish Government sent the parliament the latest draft for the Ley de Economia Sostenible (Sustainable Economy Act), which contained riders modifying the current laws on copyright and interactive services. These amendments give the Spanish Ministy of Culture the administrative power to take down websites (or order ISPs to block those hosted overseas), all without a court order and in the name of 'safeguarding Intellectual Property Laws against Internet Piracy'. For this reason some of us have written a manifesto that is being published today all over spanish weblogs and media.
Fight for your rights!
- Copyright should not be placed above citizens' fundamental rights to privacy, security, presumption of innocence, effective judicial protection and freedom of expression.
- Suspension of fundamental rights is and must remain an exclusive competence of judges. This blueprint, contrary to the provisions of Article 20.5 of the Spanish Constitution, places in the hands of the executive the power to keep Spanish citizens from accessing certain websites.
- The proposed laws would create legal uncertainty across Spanish IT companies, damaging one of the few areas of development and future of our economy, hindering the creation of startups, introducing barriers to competition and slowing down its international projection.
- The proposed laws threaten creativity and hinder cultural development. The Internet and new technologies have democratized the creation and publication of all types of content, which no longer depends on an old small industry but on multiple and different sources.
- Authors, like all workers, are entitled to live out of their creative ideas, business models and activities linked to their creations. Trying to hold an obsolete industry with legislative changes is neither fair nor realistic. If their business model was based on controlling copies of any creation and this is not possible any more on the Internet, they should look for a new business model.
- We believe that cultural industries need modern, effective, credible and affordable alternatives to survive. They also need to adapt to new social practices.
- The Internet should be free and not have any interference from groups that seek to perpetuate obsolete business models and stop the free flow of human knowledge.
- We ask the Government to guarantee net neutrality in Spain, as it will act as a framework in which a sustainable economy may develop.
- We propose a real reform of intellectual property rights in order to ensure a society of knowledge, promote the public domain and limit abuses from copyright organizations.
- In a democracy, laws and their amendments should only be adopted after a timely public debate and consultation with all involved parties. Legislative changes affecting fundamental rights can only be made in a Constitutional law.
Published on Nov. 1, 2009
I just released my first version of a Role-Based Access Control system for permissions in Django.
Development code can be found in BitBucket:
http://bitbucket.org/nabucosound/django-rbac/
The project's page is here
First of all, I would like to show some drawbacks of Django's current permission system:
- Permissions are tied directly to the User model from django.contrib.auth, so you cannot use any other existing model in your application.
- The task of mantaining this list of permissions in the current Django system is responsibility of a superuser or some other kind of centralized entity.
- You can certainly assign permissions to Group model instances, but all users in this group will share the same permissions.
- Last, but not least, until Django v1.2 will come and ticket #11010 implemented, the permission system is model-level -- it doesn't allow granular permissions (row-level), which means you can give a user authorization to do something based on all instances of a model class, but not to a single model instance (an object).
Many applications, and specially today's web applications -- which involve concepts as collaboration or content driven by the users -- need the flexibility to support delegation of permission granting to objects by other trusted agents. A clear example is a social networking site, where the users want to allow or deny access to their profiles or pictures, open or close their different communication channels like receiving friendship requests or private messages. django-rbac tries to champion this by introducing some key features from the Role-Based Access Control (RBAC) proposal. In this implementation users (subjects) are assigned different roles that, in turn, have (or not) privileges over objects. With this permission system, the owner of an object can give privileges to certain roles. For example, a user can grant access to other users trying to read some personal info only if they belong to, at least, one of the roles specified in the permission rule.
I initially developed the first version of this app for a social network, to give its users the ability to control who has privileges upon their profiles, photo albums, personal information, and such. If you are in a similar situation, you'll find that django-rbac suits perfect for your purposes. But, as long as a general-purpose access control is being implemented, even if you are building any other kind of application which needs this level of permission control, django-rbac will help you out. I think I have made it enough generic to match a wide range of use cases.
Published on Sept. 29, 2009
Introduction
Update: I realized I didn't fully explained the whole picture of the issue I am describing here, so I have added a few lines more in the introduction section.
In a project with an application named concerts that lists concerts from european cities, consider a classic two-level URLconf where the root urls.py module "includes" (i.e. uses the include method from django.conf.urls.defaults) a second URLconf module.
urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^concerts/', include('concerts.urls'))
)
concerts/urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('concerts.views',
url(regex=r'^list/$', view='my_view', name='concerts_list_all')
)
Let's say you want to extend the URLconf and have two kinds of URL to call the same view, the first to display all concerts, the second for concerts in a given city:
/concerts/list/
/barcelona/concerts/list/
/london/concerts/list/
/paris/concerts/list/
There are two situations we want to overcome in this scenario. First, only one view must be used, so a little bit of business logic must be implemented. The function behaves differently if it receives the location keyword argument or not:
concerts/views.py
def my_view(request, location=None):
if location is not None:
# filter concerts QuerySet by location, for example
else:
# query all concerts
return render_to_response('base.html', {'location': location},
context_instance=RequestContext(request))
The second one is the one that causes me to go through this workaround. As we are making use of the Django named urls, so I have to be able to use two named ursl with their respective params each one. For example, in Django template language:
{% url concerts_list %}
{% url concerts_list_location location %}
First attempt: easily discarded
urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^concerts/', include('concerts.urls'))
(r'^barcelona/concerts/', include('concerts.urls'))
(r'^london/concerts/', include('concerts.urls'))
(r'^paris/concerts/', include('concerts.urls'))
)
With this solution, I would have to create a new pattern each time a city was added to the project database. Obviously, we should remember to update the URLconf in some manual or automatic way. No way.
Second attempt: creating two urls.py
The last 3 URLs can be done easily by creating a URL pattern with a keyword argument location in the root URLconf:
urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^concerts/', include('concerts.urls'))
(r'^(?P<location>\w+)/concerts/', include('concerts.urls_location'))
)
Then we duplicate concerts/urls.py to create concerts/urls_location.py and modify this latest one to use another named URL name:
concerts/urls_location.py
from django.conf.urls.defaults import *
urlpatterns = patterns('concerts.views',
url(regex=r'^list/$', view='my_view', name='concerts_list_location')
)
If we wouldn't change the name from the url and left it the same for both files, the Django URL dispatcher would mess up.
So, if we make a request to /concerts/list/, concerts.urls would be included, and for a request like /barcelona/concerts/list/ concerts/urls_location.py would be.
But it is stupid to have two files with so small changes between them (only the url name params). Also, every modification in one of them must be replicated in the other. It sucks.
Final solution #1
concerts/urls.py
from django.conf.urls.defaults import *
base_urls = ({
'regex': r'^$',
'view': 'my_view',
'name': 'my_view',
},)
urls = [url(**base_url) for base_url in base_urls]
urlpatterns = patterns('myapp.views', *urls)
concerts/urls_location.py
from django.conf.urls.defaults import *
from myapp.urls import urlpatterns as orig_urlpatterns
new_urlpatterns = orig_urlpatterns[:]
for u in new_urlpatterns:
u.name = '_'.join([u.name, 'alt'])
urlpatterns = patterns('', *new_urlpatterns)
In the first URLconf module I create a tuple of url params dictionaries. This structure is the one to mantain. the patterns is automatically populated with it. Then, in the second one, before populating patterns we append a suffix into each url name param.
So, for example, in a template we can make unique calls:
{% url concerts_list_all %} {# renders '/concerts/list/' #}
{% url concerts_list_location "barcelona" %} {# renders '/barcelona/concerts/list/' #}
Final solution #2
I recently came to a more simple and pythonic solution which also has the advantage that concerts/urls.py can be left in the common django syntax for URLconf modules:
concerts/urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('myapp.views',
url(
regex = r'^$',
view = 'my_view',
name = 'my_view',
),
)
concerts/urls_location.py
from django.conf.urls.defaults import *
from myapp.urls import urlpatterns as orig_urlpatterns
new_urlpatterns = orig_urlpatterns[:]
for u in new_urlpatterns:
u.name = '_'.join([u.name, 'alt'])
urlpatterns = patterns('', *new_urlpatterns)
Published on Sept. 8, 2009
DRY (Don't repeat yourself) is always a good coding practice I try to follow, at least whenever deadlines allow me to do so. Even for a bunch of code bits, it helps keeping clean and modular.
Talking about views, I find myself using different techniques and approaches to write a single function that centralizes all the logic and, at the same time, behave differently, depending on who is calling it.
Sometimes it is good to overload the number of arguments it receives, and use them as indicators and flags to switch to the desired behavior. A simple example, widely used in lots of Django apps and projects, is to pass a template variable from the kwargs positional argument in a URLconf:
url(
regex=r'^$',
view='list_posts',
name='list_posts',
kwargs={'template': 'yourtemplatepath/templates/yourtemplate.html'},
)
In your view, you receive the parameter and render either the template value passed with the 'template' parameter, or the default template otherwise:
def your_view(request, template='templates/default.html'):
...
return render_to_response(template, {}, context_instance=RequestContext(request))
If you want to add functionality to certain cases, instead of modifying the base view, you better create a wrapper function, which will be called before, adding all the stuff you need to execute before or after. For instance, another trivial example would be to check something before calling the view from the example above:
def wrapper_view(request):
if request.method == 'POST':
# raise error, or whatever
...
else:
return your_view(request, template='templates/another_template.html')
While integrating my personal blog application django-nomadblog (as a good djangonaut I use my own blogging system) into this blog (Nomadblue), I needed to pull out the RequestContext creation and population done in the django-nomadblog from the rest of the logic done in the view. In this scenario, the view from django-nomadblog is the function that contains all the code logic, including the creation and population of the RequestContext object, so a simple wrapper like the one in the previous example doesn't work. I don't want to modify the view to include extra arguments, because this hack obviously would break the philosophy of the app -- that is, be reusable and modular.
A good neat solution I ended up implementing is to split each view in django-nomadblog in two, the first acting as the regular django view receiving the request and rendering the response, and the second handling all the logic related to RequestContext creating and update. Let me put an example in order to get a better picture.:
def _nomadblog_context_view(request, context=None):
"""This is the function in charge of the context"""
ctxt_dict = {
'title': 'Jazz from hell',
'author': wazoo_function(), # and so on
...
}
context = RequestContext(request, ctxt_dict) if context is None \
else context.update(ctxt_dict)
return context
def nomadblog_view(request, template='templates/default.html'):
"""call the context view before rendering the response"""
context = _nomadblog_context_view(request)
# render to response using context
return render_to_response(template, {}, context_instance=context)
The only thing left was to create a view in my nomadblue project that calls the _nomadblog_context_view. This way, I didn't need to rewrite anything, repeat myself, or hack any existing pristine app. If I am planning to use django-nomadblog in other projects, I can keep a single copy of it, let's say in a global site-packages for example, and have each project importing the same code. One day I update the version of my blog app with new features or bug fixings, and automatically all the projects get the benefits.
To have a more complete -- and probably more self-explanatory of what I tried to explain in this post -- take a lot at the views.py. You can see four views (list_posts, show_post, list_categories and list_posts_by_category) which have their related context view function respectively, equally named with a prepended underscore.
Published on Aug. 24, 2009
Updated 13 Sep 2009: The current project page for django-nomadblog can be found here
Here it is, the initial documentation for my first django app release, django-nomadblog.
Overview
This is a basic Django application implementing the most simplest form of a blog (from my point of view, of course). It has been written with an eye on keeping modularity as far as possible, so you won't find lots of goodies in the code, but just a couple of features to help you start hacking.
Features
- A mechanism to tell the application if there's gonna be only one blog or multiple blogs and users, easily configurable via a project setting and a URL pattern.
- Views are split into two functions, one for the view logic and the other in charge of creating or updating the RequestContext. This enables calling the logic behind a view without rendering the response. It is better explained below.
Installation
Soon I'll package the whole thing and upload it to PyPi for the sake of standard installations.
Mercurial checkout
Install Mercurial if you don't have it yet, and clone the repository:
hg clone http://bitbucket.org/nabucosound/django-nomadblog/
Symlink to the folder called nomadblog inside django-nomadblog from somewhere in your PYTHONPATH -- could be the system-wide site-packages python folder, or the path your virtualenv project is using, if you are using Virtualenv (which I strongly encourage). And if you do and are also using Virtualenvwrapper then you can easily add2virtualenv.
Configuration
Add nomadblog to the INSTALLED_APPS setting of your settings file.
Define the variable NOMADBLOG_SINGLE_USER in your project settings.py as True if you want a single blog configuration, or False if you will allow for multiple blog nesting. For example:
NOMADBLOG_SINGLE_USER = True
Put this code somewhere in the beggining of your root urls.py:
try:
from settings import NOMADBLOG_SINGLE_USER
except ImportError:
NOMADBLOG_SINGLE_USER = False
Include this URL pattern also in urlpatterns in your root urls.py:
(r'^blog/', include('nomadblog.urls')) if NOMADBLOG_SINGLE_USER else (r'^blogs/(?P<username>\w+)/', include('nomadblog.urls'))
Creating Templates
django-nomadblog views render four templates, one for each view (list_posts, show_post, list_categories, list_posts_by category) named after its corresponding view name, plus '.html'.
If you are happy with this layout, you can just simply create a folder called nomadblog in one of your template paths (like yourproject/templates/nomadblog) and include these four template files.
If you otherwise prefer any other templates, you can override the template variable each view receives by passing it through the kwargs in the URLconf:
url(
regex=r'^$',
view='list_posts',
name='list_posts',
kwargs={'template': 'yourtemplatepath/yourtemplate.html'},
)
Introspecting nomadblog.views will give you the clue on what context each template is going to receive.
Creating custom wrappers for views
If you want to extend functionality beyond the basic logic behind a django-nomadblog view, you can call the underscored version of the view. Passing a Django RequestContext the function will update it with the expected values needed for rendering the response. If the username parameter is passed, an extra filter will be used in the Django ORM calls -- you may pass it if you are in a multiuser configuration. If you do not pass any RequestContext object, a new one is created and returned.
So, for instance, say you want to wrap around list_post view:
from django.shortcuts import render_to_response
from nomadblog.views import _list_posts
def your_view(request, username=None):
context = _list_posts(request, username=username)
return render_to_response('your_temaplate.html', {}, context_instance=context)
A comment on categories model
This model is included to allow one -- and only one -- category for each blog post. I could have ommited this feature and delegated it to other parts such as django-tagging. But first, all I needed when I was writing was one category to start up the blog quickly. And second, although I always try to keep my code clean and simple, I as well fancy the "batteries-included" concept Python and Django praise. So finally I included the model in the first version of this application for the sake of the former statements. I don't think it'll annoy people implementing their own category system, theirs and this can cohabit smoothly.
Published on Aug. 2, 2009
A whole weekend doing some fun coding has produced this brand new kid on the blogosphere. Soon I will write my first "real" post, in the meantime I can't wait to leave the URL to django-nomadblog, the django app that I built to run this weblog:
http://bitbucket.org/nabucosound/django-nomadblog
You will need Mercurial to clone it out. Hasta pronto!