Find the required permissions of Django URLs without calling them? - django

My Django app currently has URLs which are protected by 'permission_required()' functions.
This function is called in three different ways.
As a decorator in views.py, with hardcoded parameters.
As a plain function, with autogenerated parameter, in custom Class Based Generic Views.
As a function invoking views in urls.py, with hardcoded parameters.
I'm now adding a menu system to the app, and I need to make menu entries reflect whether the user has permission to request the URL of each menu entry. (Either by greying-out or hiding said entries.)
Is there a way of query the permissions required to a URL without requesting the URL?
The only solution I've thought of so far is to replace the decorator with a parameterless 'menu_permssion_required()' decorator and hardcode all of the permissions into a Python structure. This seems like a step backwards, as my custom Class Based Generic Views already autogenerate their required permissions.
Any suggestions on how to make a menu system which reflects URL permissions for the current user?

Here is an example of how to solve your problem:
First, Create a decorator wrapper to use instead of permission_required:
from django.contrib.auth.decorators import login_required, permission_required, user_passes_test
from django.core.exceptions import PermissionDenied
from functools import wraps
from django.utils.decorators import available_attrs
def require_perms(*perms):
def decorator(view_func):
view_func.permissions = perms
#wraps(view_func, assigned=available_attrs(view_func))
def _wrapped_view(request, *args, **kwargs):
for perm in perms:
return view_func(request, *args, **kwargs)
raise PermissionDenied()
return _wrapped_view
return decorator
Then, use it to decorate your views:
#require_perms('my_perm',)
def home(request):
.....
Then, add a tag to use for your menu items:
from django.core.urlresolvers import resolve
def check_menu_permissions(menu_path, user):
view = resolve(menu_path)
if hasattr(view.func, "permissions"):
permissions = view.func.permissions
for perm in permissions:
if user.has_perm(perm):
return True # Yep, the user can access this url
else:
return False # Nope, the user cannot access this url
return True # or False - depending on what is the default behavior
And finally, in your templates, when building the menu tree:
<button href="{{ some_path }} {% if not check_menu_permissions some_path request.user %}disabled="disabled"{% endif %} />
N.B. I've not tested the last part with the tag, but I hope you got the idea. The magic thing here is to add the permissions to the view_func in the decorator, and then you can access this using resolve(path). I'm not sure how this will behave in terms of performance, but after all that's just an idea.
EDIT: Just fixed a bug in the example..

Is there a way of query the permissions required to a URL without requesting the URL?
User.has_perm() and User.has_module_perms()
Any suggestions on how to make a menu system which reflects URL permissions for the current user?
I really like this question, because it concerns anyone that makes a website with django, so I find it really relevant. I've been through that myself and even coded a menu "system" in my first django project back in 2008. But since then I tried Pinax, and one of the (so many) things I learnt from their example projects is that it is completely unnecessary bloat.
So, I have no suggestion which I would support on how to make a menu "system" which respects the request user permissions.
I do have a suggestion on how to make a simple menu which respects the request user permissions, so that might not be completely unrelated.
Just make your menu in plain HTML, it's not like it's going to change so often that it has to be generated. That will also keep your Python code simpler.
Add to settings.TEMPLATE_CONTEXT_PROCESSORS: 'django.core.context_processors.PermWrapper'
Use the {{ perms }} proxy to User.has_perms.
Example:
{% if perms.auth %}
<li class="divider"></li>
{% if perms.auth.change_user %}
<li>
{% trans 'Users' %}
</li>
{% endif %}
{% if perms.auth.change_group %}
<li>
{% trans 'User groups' %}
</li>
{% endif %}
{% endif %}
{# etc, etc #}
That's how I keep navigation simple, stupid, and out of the way. But also I always include an autocomplete not far from the menus to allows the user to navigate to any detail page easily. So, that's all I know about navigation in django projects, I'm eager to read other answers !

I had a similar issue, but it went a little deeper. Instead of just permissions, I also wanted other tests based on the lidded in user (ie, is_staff, or user.units.count() > 1). Duplicating these in the view and the template seems prone to errors.
You can introspect a view object, and see all of the decorators wrapping it, and work out if they are checks (in my case: the first argument I'd u or user). If they all pass, then allow rendering the link.
Get all decorators wrapping a function describes the technique in a little more detail. You can find the app that wraps this up into a handy replacement for {% url %} at Django-menus.

Related

How to match different content on a page according to which user is logged-in?

I just started using django and I have some problems understanding how to use auth on my web app. So, basically, what I cannot understand how to implement is displaying different content on my page for each user
My app is an online editor that each user can use to write their code and have it stored. I have implemented the sign up/sign in and what I need to do now is to have a different filesystem for each user and display it appropriately.
I don't know why I can't find this answer anywhere but I am really overwhelmed with this problem and I have done zero progress.
You have 2 easy ways to do this:
1 - Inside template
2 - Inside Views
Which to prefer when:
Template - When you have less content to be segregated then go with template way.
How to do that?
`{% if user.is_superuser %}
<some html>
#Your html for Superuser
#you can also include a another html file
{% include "App_name/Superuser_view.html" %}
{% else %}
<some html>
#Your html for Staff or whoever
#you can also include a another html file
{% include "blazon/employee_view.html" %}
{% endif %}`
Inside Views : when you need to render lot of html differences among the user types then go with this method.
def view(request):
if request.user.is_superuser():
#your View Function & return it individually
elif request.user.is_admin():
#your View Function
else request.user.is_staff():
#your View Function
You can check what permissions does a user have and implement different logic in view for different types of users:
def some_view(request):
if request.user.is_admin:
# logic for Admin users
elif request.user.is_staff:
# logic for Staff only
else:
# logic for all other users
If you want to implement your custom permissions you can check docs.

django context_processor not understood in templates

i cant quite find it so i hope someone can help me out.
I found the option of using the
TEMPLATE_CONTEXT_PROCESSORS = ("django.contrib.auth.context_processors.auth" )
In django (1.5). But now its not clear for me how i should use it. Should i still put the request in my views, or can i with this enabled use the user_object in my template without sending an extra variably with the Requestcontect
For example:
My view at the moment:
def user_characters(request, user_id):
characters = Character.objects.filter(user=user_id)
user = User.objects.get(id=user_id)
return render_to_response('characters.html',
{'characters': characters, "user": user},
context_instance=RequestContext(request))
My template:
{% extends "base.html" %}
{% block mainframe %}
{% if characters|length < 3 %}
<p>New Character(WN)</p>
{% endif %}
And then the rest of my view.
I notice in almost every view i make i want the user_object send with it.
Can someone please give me an example of how this works?
With kind regards
Hans
django.contrib.auth.context_processors.auth context processor is enabled by default, you don't have to add anything. When you use RequestContext(), a context variable user is available in all templates that you can use. To get id {{userd.id}}.
To check user is authenticated or not, do
{% if user.is_authenticated %}
{# handle authenticated user #}
{%else%}
{# handle anonymous non-authenticated users #}
{%endif%}
You should not expose the user id in the url, you wont need it anyway, if you use django sessions- and the authentication framework. You can always check the logged in user via request.user in your serverside view. With the context processor your should be able to access the user with user.desiredattribute, but you should not need it for the url you try to create.
The docs on this seem pretty clear to me:
https://docs.djangoproject.com/en/dev/ref/templates/api/#django.template.RequestContext
If you want context processors to function, you must ensure that you're using a RequestContext instance. You can do that by explicitly creating it in your views, as you show, or (more conveniently, in my opinion) by using the render shortcut rather than render_to_response as documented here:
https://docs.djangoproject.com/en/dev/topics/http/shortcuts/#render
With the django.contrib.auth.context_processors.auth context processor in place, the user will always be available in the context variable user. At least, assuming your template is being rendered with a RequestContext instance.
You absolutely should not trust a variable obtained from the URL to determine the user if you have any kind of controlled information. With the system you have shown, anyone can view anyone's data simply by editing the URL. That might be OK for a totally insecure application, but it's much more normal to look at request.user.

Django - Showing different templates to admins

In Django what's the best way to implement templates with extra functionality for users with 'admin' permissions.
I'm not sure if I should create a set of completely different views specific for admins or integrate it into my existing views and templates like 'if user is an admin' everywhere.
Is there a standard way to do this in Django?
This will show the stuff only if you are active and staff not admin:
{% if request.user.is_active and request.user.is_staff %}
{% include "foo/bar.html" %}
{% endif %}
If you wanna show only and ONLY for admin you have to do that:
{% if request.user.is_superuser %}
ADD your admin stuff there.
{% endif %}
Differences about these fields here.
If you have the the user available in template context you can do:
{% if user.is_active and user.is_staff %}
Only the admin will see this code. For example include some admin template here:
{% include "foo/bar.html" %}
{% endif %}
User will be available in your template f you use RequestContext and your TEMPLATE_CONTEXT_PROCESSORS setting contains django.contrib.auth.context_processors.auth, which is default. See authentication data in templates as reference.
I'm an advocate of keeping as much logic out of the view layer (speaking generally about the MVC Design Pattern). So why not use decorators to direct your user to different views based upon their privilege? In your urls.py, define a pattern for admins:
url(r'^admin/$', 'user.views.admin_index'),
#do so for your other admin views, maybe more elegantly than this quick example
Then define a decorator to kick the user out if they're not an admin
def redirect_if_not_admin(fn):
def wrapper(request):
if request.user.is_staff():
return fn(request)
#or user.is_superuser(), etc
else:
return HttpResponseRedirect('/Permission_Denied/')
return wrapper
And in your admin views
#redirect_if_not_admin
def index(request):
##do your thing
It's more code than the other two answers, which are not wrong. It's just a personal preference to keep clutter down in the views.

Django Dynamic menu design question

I want to create dynamic menus according to user permissions. As was already discussed here and by the the documentation itself, I know that I can achieve this in the templates using the following snippet:
{% if perms.polls.can_vote %}
<li>
Vote
</li>
{% endif %}
But the problem is that for security reasons I want to limit the access to the views too. The snippet that I found in the documentation is the following:
from django.contrib.auth.decorators import permission_required
def my_view(request):
# ...
my_view = permission_required('polls.can_vote', login_url='/loginpage/')(my_view)
Isn't this against DRY principle? Isn't there a way to define only in one place what is the permission needed for each url? Perhaps in urls.py?
EDIT: (See end of post for the original text of the answer with the initial, simple idea.)
After being kindly stricken with a cluebat (see the OP's comment below), I find I can see more to the problem than before. Sorry it took so long. Anyway:
Would this kind of template be alright for you?
{% for mi in dyn_menu_items %}
{% if mi.authorised %}
<a href={{ mi.url }}>{{ mi.title }}</a>
{% endif %}
{% endfor %}
To make this work on the Python side, you could use RequestContext in your views with a custom context processor setting the dyn_menu_items variable appropriately. In case some background information is required, the Advanced Templates chapter of the Django Book introduces RequestContext, shows how to use it with render_to_response (kinda important :-)) etc.
Also, I guess at this point it could be useful to put the view functions responsible for the locked-up sections of your site in a list somewhere:
_dyn_menu_items = [(url1, view1, title1, perm1), ...]
Then you could map a couple of functions, say prepare_pattern and prepare_menu_item across that list, having it work roughly like so:
def prepare_pattern(menu_item):
url1, view, title, perm = menu_item
pattern = PREPARE_URLCONF_ENTRY_SOMEHOW(...) # fill in as appropriate
return pattern
def prepare_menu_item(menu_item):
url, view, title, perm = menu_item
mi = PREPARE_THE_BIT_FOR_REQUESTCONTEXT(...) # as above
return mi
These could be combined into a single function, of course, but not everybody would find the result more readable... Anyway, the output of map(prepare_menu_item, _dyn_menu_items) would need to be a dictionary to be passed to your views by a helpful context processor (the figuring out of which, it being the slightly tedious bit here, I'll leave to you ;-)), whereas the output of map(prepare_pattern, _dyn_menu_items), let's call it dyn_menu_patterns, would be used in patterns('', *dyn_menu_patterns), to be used in your URLconf.
I hope this makes sense and is of some help...
THE PRE-EDIT ANSWER:
Based on your short description, I'm not sure what solution would be best for you... But if the permission_required snippet does what you want, just not DRY-ly enough, how about rolling your own wrapper:
def ask_to_login(perm, view):
return permission_required(perm, login_url='/loginpage/', view)
You could put this anywhere, including in URLconf. Then you could replace all mentions of '/loginpage/' with reference to a variable defined towards the top of your URLs file and you'd have yourself a solution with a single mention of the actual login URL, for one-place-only update of said URL should you have to move it around. :-)
Of course the views would still need to be wrapped explicitly; if that bothers you, you could try to make ask_to_login into a decorator for easy wrapping at the definition site. (But perhaps it's really best not to do it, lest you force yourself to dig your views from under the decorator in case you need them undecorated at some point in the future.)
I'm aware this question was asked a couple of weeks ago now, but you mentioned http://code.google.com/p/greatlemers-django-tools/ in one of your comments so I thought I'd chip in.
The project is still active (although it's slightly on the backburner at the moment) but I'm not sure if it is as DRY as you're after. You would still have to specify permissions twice, once in the model object for the menu item and once on the view. This isn't necessarily a bad thing however as the permissions that you define on the menu item may be slightly different from those on the view.
If you wanted to do everything in one place I'd probably suggest a combination of a utility function for use in urls.py that can add restrictions to a view whilst also storing said restriction somewhere for use with a special template tag. I'd imagine it may look something like this.
# Stored in a file named access_check_utils.py say.
from django.conf.urls.defaults import url
from django.core.urlresolvers import get_callable
from django.contrib.auth.decorators import permission_required
access_checked_urls = {}
def access_checked_url(regex, view, kwargs=None, name=None, prefix='', perms=None, login_url=None):
if perms is None:
perms = []
callback = None
if callable(view):
callback = view
elif isinstance(view, basestring):
if prefix:
view_path = "%s.%s" % (prefix, view)
else:
view_path = view
try:
callback = get_callable(view_path)
except:
callback = None
if callback is not None:
# Add all the permissions
for perm in perms:
callback = permission_required(perm, login_url=login_url)(callback)
if name is not None:
access_checked_urls[name] = perms
else:
callback = view
return url(regex, callback, kwargs=kwargs, name=name, prefix=prefix)
That should work for the pit needed in urls.py called the same way as you would with a normal url but with the added perms and login_url parameters (perms should be a list of all the relevant ones).
# In a templatetag folder somewhere
from django import template
from django.core.urlresolvers import
# This needs to point to the right place.
from access_check_utils import access_checked_urls
register = template.Library()
#register.inclusion_tag("access_checked_link.html", takes_context=True)
def access_checked_link(context, title, url, *args, **kwargs):
perms = access_checked_urls.get(url, [])
if not perms:
allowed = True
else:
allowed = context.request.user.has_perms(perms)
return { 'allowed': allowed,
'url': reverse(url, *args, **kwargs),
'title': title }
This would have an associated template file like:
{% if allowed %}{{ title }}{% endif %}
I've not tested this fully, but it should work (or at least be a good basis for something that should work). I'll probably even look to adding something like this into gdt_nav allowing it to check for these base permissions if they exist, and then checking for any extras added.
Hope this is of some help.
--
G

Django: How can I identify the calling view from a template?

Short version:
Is there a simple, built-in way to identify the calling view in a Django template, without passing extra context variables?
Long (original) version:
One of my Django apps has several different views, each with its own named URL pattern, that all render the same template. There's a very small amount of template code that needs to change depending on the called view, too small to be worth the overhead of setting up separate templates for each view, so ideally I need to find a way to identify the calling view in the template.
I've tried setting up the views to pass in extra context variables (e.g. "view_name") to identify the calling view, and I've also tried using {% ifequal request.path "/some/path/" %} comparisons, but neither of these solutions seems particularly elegant. Is there a better way to identify the calling view from the template? Is there a way to access to the view's name, or the name of the URL pattern?
Update 1: Regarding the comment that this is simply a case of me misunderstanding MVC, I understand MVC, but Django's not really an MVC framework. I believe the way my app is set up is consistent with Django's take on MVC: the views describe which data is presented, and the templates describe how the data is presented. It just happens that I have a number of views that prepare different data, but that all use the same template because the data is presented the same way for all the views. I'm just looking for a simple way to identify the calling view from the template, if this exists.
Update 2: Thanks for all the answers. I think the question is being overthought -- as mentioned in my original question, I've already considered and tried all of the suggested solutions -- so I've distilled it down to a "short version" now at the top of the question. And right now it seems that if someone were to simply post "No", it'd be the most correct answer :)
Update 3: Carl Meyer posted "No" :) Thanks again, everyone.
Since Django 1.5, the url_name is accessible using:
request.resolver_match.url_name
Before that, you can use a Middleware for that :
from django.core.urlresolvers import resolve
class ViewNameMiddleware(object):
def process_view(self, request, view_func, view_args, view_kwargs):
url_name = resolve(request.path).url_name
request.url_name = url_name
Then adding this in MIDDLEWARE_CLASSES, and in templates I have this:
{% if request.url_name == "url_name" %} ... {% endif %}
considering a RequestContext(request) is always passed to the render function. I prefer using url_name for urls, but one can use resolve().app_name and resolve().func.name, but this doesn't work with decorators - the decorator function name is returned instead.
No, and it would be a bad idea. To directly refer to a view function name from the template introduces overly tight coupling between the view layer and the template layer.
A much better solution here is Django's template inheritance system. Define a common parent template, with a block for the (small) area that needs to change in each view's version. Then define each view's template to extend from the parent and define that block appropriately.
If your naming is consistent in your urls.py and views.py, which it should be, then this will return the view name:
{{ request.resolver_match.url_name }}
Be sure to apply some context to it when you call it in the template. For example, I use it here to remove the delete button from my detail view, but in my update view the delete button will still appear!
{% if request.resolver_match.url_name != 'employee_detail' %}
Since Django 1.5 you can access an instance of ResolverMatch through request.resolver_match.
The ResolverMatch gives you the resolved url name, namespace, etc.
one simple solution is :
def view1(req):
viewname = "view1"
and pass this viewname to the template context
def view2(req):
viewname = "view2"
and pass this viewname to the template context
in template access the viewname as
{{viewname}}
and also you can use this in comparisons.
I'm working on this for a help-page system where I wanted each view to correspond to a help-page in my cms with a default page shown if no help page was defined for that view. I stumbled upon this blog where they use a template context processor and some python inspect magic to deduce the view name and populate the context with it.
This sounds like the perfect example of a generic view that you can set up.
See the following resources:
Django Book - Chapter 11: Generic Views
Django Docs -Tutorial: Chapter 4
Django Docs - Generic Views
These links should help you simplify your views and your templates accordingly.
If you're using Class Based Views, you most likely have a view variable you can access.
You can use several methods from that to determine which view has been called or which template is being rendered.
e.g.
{% if view.template_name == 'foo.html' %}
# do something
{% else %}
# other thing
{% endif %}
Another option is to take out the piece of the template where you need something to change and make it into a snippet and then use {% include 'my_snippet.html' with button_type = 'bold' %} in your templates, sending arbitrary values to the snippet so it can determine what to show / how to style itself.
Most generic views — if not all — inherits the ContextMixin which adds a view context variable that points to the View instance.
In your template, you can access the current view instance like this:
{{ view }}
Define class_name method in your view
class ExampleView(FormView):
...
def class_name(self):
return self.__class__.__name__
You can get the class name of the current view in a template like this:
{{ view.class_name }}
{% if view.class_name == "ExampleView" %} ... {% endif %}
Why not trying setting up a session cookie, then read the cookie from your template.
on your views set cookies
def view1(request):
...
#set cookie
request.session["param"]="view1"
def view2(request):
request.session["param"]="view2"
then in your ONE template check something like..
{% ifequal request.session.param "view1" %}
... do stuff related to view1
{% endifequal %}
{% ifequal request.session.param "view2" %}
... do stuff related to "view2"
{% endifequal %}
Gath