Hi all,

I have been using django for a while and became happy by the time I 
discovered the auth module that supports permission handling. But this 
module turned out to only be able to handle model based permissions. I 
could not imagine django of not having such a basic functionality (in my 
opinion) despite of having so much other great abilities. So I started to 
search for it but eventually figured out that the auth model's code was 
prepared for implementing this but it haven't been done yet.
So I decided to write a patch for this on my own.
Currently I'm writing this patch but there are several design decisions to 
make so I wanted to share this with you and hear your opinions.

First of all: I think the main problem of this implementation is to link 
the objects with the corresponding permissions. With model based 
permissions that's easy because you only have to store a permission once 
with the models ContentType and relate with a ManyToManyField to them and 
that's it. The problem with object based permissions is that every object 
needs to have his own set of permissions and you can't just use ForeignKeys 
or ManyToManyFields from a permission model because in the process of 
creating the permission model (and table) you don't know about the models 
that will provide object permissions therefore you can't refer to them.
So I tried some different implementations.

At first I tried to used dynamic models (e.g. this project makes use of 
them: http://pypi.python.org/pypi/django-object-permissions): The idea is 
to create intermediate models like 'MyModel_ObjectPermissions' that stores 
the object permissions with foreign keys to the model itself, user and 
group.
But this has a huge disadvantage: the use of dynamic models.
In fact thinking as database specialist that is the easiest way of 
connecting the model instances to the permissions but dynamic models are 
very sensitive and kind of hacky in my opinion and I think that does not 
match well with django's ideas.

Then I found out about GenericRelations from the contenttypes framework. So 
you could possibly use a single model called 'ObjectPermissions' or 
something and link users, permissions and instances of all types of models 
and only had to use one GenericRelation. This solution eliminates the 
problem wit the dynamic models because it doesn't even make use of them. 
But the GenericRelations have another not negligible disadvantage: The 
databases behind django don't have native support for them. I thought of 
huge django projects handling thousands and thousands of object 
permissions. I think these GenericRelations wouldn't be such scalable to 
make use of them.

The only solution for me was to find a way to link the (unknown) model 
instances to the permissions in the reversed direction. So not use 
ForeignKeys, etc. in the permission model to refer to the unknown model but 
to refer from the model to the permission itself. That would fix the 
problem of not knowing the models while creating the permission model. So 
in the end I thought of following:
- there is a new model in the auth module called 'ObjectPermission' this 
model has ManyToManyFields to User and Group and a ForeignKey to Permission
- instead of ObjectPermission referring to the model using object 
permissions, a field called 'object_permissions' is added to the 
corresponding models (by use of the class_prepared signal) (dynamically 
adding fields is way better than use completely dynamic models in my 
opinion)
- the object_permissions field is a ManyToManyField, that refers to 
ObjectPermission. In fact, a 'ManyToOneField' would be sufficient but 
django only has one to many fields (the ForeignKeyField) and we can't just 
use this in the reversed direction, as I mentioned above
This picture illustrates the relations:

<https://lh6.googleusercontent.com/-4wiWd_3CYFc/T4i4ZgfPKeI/AAAAAAAAAAM/iCqyCLwKQBA/s1600/object_permissions_models.png>


Furthermore I thought of slightly modifying the auth module (apart from the 
ObjectPermission model) in the following way:
- when the auth app is initialized a function is registered to listen to 
the class_prepared signal. This function adds the object_permissions field 
to each model, that has the Meta.object_permissions set to True (for this 
to work, this meta attribute has to be set in django.db.models.options)
- the User model gets the methods grant_perm and revoke_perm that takes the 
permission and as optional argument the object in order to simplify the 
process of handling permissions
- in the ModelBackend the methods has_perm, etc. have to be modified to be 
able to handle function calls with given objects (obviously)

So that was the technical part.

Now I want you to give feedback if this implementation is viable and maybe 
sometimes may get into django.


Thanks,
Moritz

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

Reply via email to