Django - Showing different templates to admins - django

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.

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.

reusing views inside other views in Django

I have a few components on my website that appear on many pages. DRY in mind, I would like to factor them out in separate snippets that I can include in the views that need them.
If it were only static items, then an {% include "snippet.html" %} would be the perfect solution. How can achieve a similar thing for snippets that include forms (and hence logic in the view) or require calculations before being displayed? Also, I would like to be able to nest the snippets several levels deep.
I know I can put simple logic in the template, using {% if ... %} ... {% endif %} blocks, but this turns into horrible spagetthi very soon and I want to keep the business logic separated from the presentation logic.
I am imagining a pattern as follows (here with oversimplified business logic):
def view1(request):
"Display some data"
total = get_total_vote_count()
return render(request, 'snippet1.html', {'total': total})
def view2(request, pk):
"Display some data about the article with primary key pk."
votes = get_votes_for_article(pk)
render1 = view1(request)
return render(request, 'snippet2.html', {'votes': votes, 'render1': render1})
def view3(request, pk):
"Display article pk and some additional data from view1 and view2":
article = get_object_or_404(Article, pk=pk)
render2 = view2(request, pk)
return render(request,
'article.html',
{'article': article, 'render2': render2},
)
with the templates something like:
# in snippet1.html:
{{ total }}
# in snippet2.html:
<p>Votes for this article: {{ votes }} out of {{ render1 }} total votes.</p>
# in page.html:
{% extends "base.html" %}
{% block "content" %}
<h1>article.title</h1>
<p>article.text</p>
<small>{{ render2 }}</small>
{% end block "content" %}
Note that there will be more views that will use view1 and view2 (e.g. an overview of the votes for all articles); that is why I have factored them out in separate functions.
How can I make this work?
Or is there a better trick in the Django toolbox to make this work without repeating view1 and view2 every time I want to use the same snippets in other views?
This is what custom template tags - specifically, inclusion tags - are for: rendering a template fragment with its own context.
what about django middleware, you can use middleware for this case. view1 and view2 repeating every time right ?. then attach the render1 and render2 to your request.
Middleware is a framework of hooks into Django’s request/response processing. It’s a light, low-level “plugin” system for globally altering Django’s input or output.
https://docs.djangoproject.com/en/dev/topics/http/middleware/

Find the required permissions of Django URLs without calling them?

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.

How to reset user password from the admin interface

In my website, I want to let the admins reset the password of any user.
With reset I mean exactly what the password_reset view does (under contrib.auth): Send a confirmation link to that user email.
How would be the best way of doing that? Is there an already app/snippet that does that?
Edit:
Let's suppose user john is an admin. What I want is to let john reset any user's password through the admin interface. For example, to reset max password, he will just go to the max user, and click on any link to reset his password.
What I finally did was to add a custom ModelAdmin:
from django.contrib.auth.forms import PasswordResetForm
from django.contrib.auth.admin import UserAdmin
class CustomUserAdmin(UserAdmin):
...
def reset_password(self, request, user_id):
if not self.has_change_permission(request):
raise PermissionDenied
user = get_object_or_404(self.model, pk=user_id)
form = PasswordResetForm(data={'email': user.email})
form.is_valid()
form.save(email_template_name='my_template.html')
return HttpResponseRedirect('..')
def get_urls(self):
urls = super(UserAdmin, self).get_urls()
my_urls = patterns('',
(r'^(\d+)/reset-password/$',
self.admin_site.admin_view(self.reset_password)
),
)
return my_urls + urls
and I also had to override the change_form.html template, like this:
{% extends "admin/change_form.html" %}
{% load i18n %}
{% block object-tools %}
{% if change %}{% if not is_popup %}
<ul class="object-tools">
{# You can also give a name to that pattern and refer to it below using 'url' #}
<li>Reset password</li>
<li>{% trans "History" %}</li>
{% if has_absolute_url %}
<li><a href="../../../r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">
{% trans "View on site" %}</a>
</li>
{% endif%}
</ul>
{% endif %}{% endif %}
{% endblock %}
The result looks like this:
If you want a more detailed explanation, I blogged about it.
The passreset app just exposes the django views via urls.py, and adjusts the login template to show a "Forgot my password" link.
The built-in django password reset views and templates are meant for self-reset. I guess the reset form could be prepopulated with a different user's email address (in the query string) but you'd still need to make adjustments such as changing the email template - "You're receiving this e-mail because you requested a password reset for your user account" is probably not what you want:
https://code.djangoproject.com/browser/django/trunk/django/contrib/admin/templates/registration/password_reset_email.html
Therefore you should expose the views at different URLs if you want to include self-reset as well.
Hook the django views into urls.py like so:
urlpatterns += patterns('django.contrib.auth.views',
url(r'^accounts/password/reset/$',
'password_reset',
name='password-reset'),
url(r'^accounts/password/reset/done/$',
'password_reset_done',
name='password-reset-done'),
url(r'^accounts/password/reset/confirm/(?P<uidb36>[-\w]+)/(?P<token>[-\w]+)/$',
'password_reset_confirm',
name='password-reset-confirm'),
url(r'^accounts/password/reset/complete/$',
'views.password_reset_complete',
name='password-reset-complete')
)
and where you want to make adjustments, pass in e.g. your own email template:
url(r'^/accounts/password/reset/$',
'password_reset',
{'email_template_name': 'my_templates/password_reset_email.html'}
name='password-reset'),
The "password_reset" view has more parameters you can tweak:
https://docs.djangoproject.com/en/dev/topics/auth/#module-django.contrib.auth.views
("post_reset_redirect" comes to mind as another one for your purposes)
To show a corresponding link you'd either change the User admin (careful, already registered - unregister then register your own, subclassed plus additional link field) or the change_form template itself.
I'm unaware of an app that provides this out-of-the-box, so I upvoted the question :-).
Yep, there is an app for that. Check here:
https://github.com/bendavis78/django-passreset

Is it possible automatically include user to all templates?

I have project in Django 1.3. In order to show username in all pages I use such tags in base.html
{% if user.is_authenticated %}
<p>Welcome, {{ user.username }}.
loggout</p>
{% else %}
loggin
{% endif %}
But if I dont return context_instance=RequestContext(request) from view value of user in template is empty. The 'django.contrib.auth.context_processors.auth' is included to TEMPLATE_CONTEXT_PROCESSORS.
Is it possible automaticaly include user to all templates?
since django 1.3. use shortcuts.render function and dont warry about requestcontext including to your views
You've given the answer yourself. As long as you use a RequestContext, it will be included in all templates.
If you really find that too much work, you could use the (new in 1.3) TemplateResponse class.
Or simply create a context processor. See
http://docs.djangoproject.com/en/dev/ref/templates/api/#writing-your-own-context-processors
Put this in context_processor.py
def root_categories(request):
return {
'user': request.user,
}
in settings.py add the context processor.
now in your template try: {{ user }}