Add to the django request.user variable - python

In django, I use the authenticate() function to log users in. Using request.user, I can access the logged in user's information which is pulled from the users table. If I do request.user.id, I can get the user's id. In any template, on any request, I can do user.username to get the username.
Is there a way by which I can add values to the request.user variable so that I can use them throughout my application and in templates?
For example, I would like to have this: request.user.timezone set when the user logs in to the site; I should be able to access this variable in templates and in my views.

You can write a simple middleware:
class UserTZMiddleware(object):
def process_view(self, request, view_func, view_args, view_kwargs):
if request.user.is_authenticated():
request.user.timezone = evaluate_tz()
and then append this into MIDDLEWARE_CLASSES in your settings.py file:
MIDDLEWARE_CLASSES = (
....,
'myapp.UserTZMiddleware',
)

Would you like to let the user change it time-zone and force a specific time-zone ? I assume you would, if so you would like to keep the timezone configurable in your database. Therfore I would suggest you to make a UserProfile model which has one to one relations with the User Object.
You can do :
class UserProfile(models.Model):
user = models.OneToOneField(User)
time_zone = models.whateverField()
... add anything else you would like to extend your profile ...
On your templete you will be able to get the timezone by doing that :
{{ request.user.userprofile.time_zone }}
Simple and very clean.
If you would like to have an automatic creation of your userprofile whenever you save a User object, you can use signals for that.

Add the request context processor to your TEMPLATE_CONTEXT_PROCESSORS. This processor adds the request to the context, in your template you can do {{request}} or {{ request.user }}
see: https://docs.djangoproject.com/en/dev/ref/templates/api/#django-core-context-processors-request

Use sessions, which are designed to keep variables in the context.
You should not change request.user as this is something that other applications will rely on and one that is populated by django's own auth machinery.
If you need to keep track of the timezone specifically, you should read up on the timezone support in django 1.4. In the documentation it provides examples for setting and managing timezones for users.

Related

How to prevent users from seeing data that does not belong to them in Django DetailView?

I have a web app where a user signs in and begins entering items for a ToDoList. The base.html is wrapped in an is_authenticated check so users cannot see anything in the app until they have logged in. I was doing some testing with:
Logging in as User2
Adding a new ToDoListItem
Redirecting to the DetailView
In this case, the URL = http://localhost:8000/to_do_list/to_do_item/72
At this point I realized that the DetailView would allow User2 to see the details for any ToDoListItem for User1 just by entering in an existing pk into: http://localhost:8000/to_do_list/to_do_item/<int:pk>.
urls.py includes
path('to_do_item/<int:pk>', views.ToDoListItemDetail.as_view(), name='todo-item-detail'),
views.py
class ToDoListItemDetail(DetailView):
model = ToDoListItem
todolistitem_detail.html
{% extends 'base.html' %}
{% block content %}
Home
<h1>DetailView for 'ToDoListItem' model</h1>
<p>TaskTitle: '{{ object.title }}'</p>
<p>Complete: '{{ object.is_complete }}'</p>
<p>User: '{{ object.user}}'</p>
{% endblock %}
What is the recommended way to prevent this from happening? I am considering the following:
I could completely remove the DetailView and direct to a different URL that only returns the user's data (using something like ToDoListItem.objects.filter(user=request.user))
I could check that the name of the user logged in matches the name of the user that owns the ToDoListItem.
I could override get_context_data() for the DetailView and check user ownership there (similar to no. 1, but within the DetailView)
??? (Something else better than the above I do not know about yet)
Is there a way to limit a user to only see their own data throughout an application without implementing this logic every time it is needed?
You can filter in the DetailView as well, by overriding the get_queryset method [Django-doc]:
from django.contrib.auth.mixins import LoginRequiredMixin
class ToDoListItemDetail(LoginRequiredMixin, DetailView):
model = ToDoListItem
def get_queryset(self, *args, **kwargs):
return super(ToDoListItemDetail, self).get_queryset(
*args, **kwargs
).filter(user=self.request.user)
Django will, behind the curtains, always call get_queryset(..). By default this function returns the queryset of the model you specified with all objects. But you thus can filter it further down.
Django's get_object method [Django-doc] will then further filter it down with the id and/or slug, but if you already filter out the elements that do not belong to the self.request.user, then this can thus only result in an query returning no results.
It also makes sense to here add the LoginRequiredMixin [Django-doc] to your class, since in case the user did not log in, you probably want to redirect hem/her to the login screen.
There is a permission named: ¨can read¨ that allow you to handle the access. For example:
class FruitEdit(PermissionRequiredMixin,DetailView):
permission_required = 'app.read_fruit'
...
I hope you can solve it

where django store request['user'] in what file

As mentioned in the documentation, authenticated user's object is stored within user variable in templates. i need where django stored user variable in apps file thanks:
user = request.user
request['user'] = user #where is?
thanks for help
It's in the AuthenticationMiddleware.
The official doc mentioned it:
link:
AuthenticationMiddleware associates users with requests using
sessions.
link:
class AuthenticationMiddleware
Adds the user attribute, representing
the currently-logged-in user, to every incoming HttpRequest object.
See Authentication in Web requests.
source code(django.contrib.auth.middleware.py):
class AuthenticationMiddleware(object):
def process_request(self, request):
assert hasattr(request, 'session'), "The Django authentication middleware requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.sessions.middleware.SessionMiddleware'."
request.user = SimpleLazyObject(lambda: get_user(request))
Make sure you're using RequestContext. Otherwise user is not available in the templates.

How to do a DetailView of Users in Django?

I currently have a DetailView for Django's built-in User.
url(
r'^users/(?P<pk>\d+)/$',
DetailView.as_view(
model = User,
template_name = 'doors/users/detail.html'
),
name = 'users_detail'
)
But when I access user in the template, it brings up the current logged in user, not the user with the pk that I pass from DetailUser. Do I need to tell DetailUser to rename the user variable to something else? And if so, how do I do that?
The django.contrib.auth.context_processors.auth sets the {{ user }} template context variable to either request.user or AnonymousUser. So, it overrides the {{ user }} context variable created by your DetailView:
def auth(request):
"""
Returns context variables required by apps that use Django's authentication
system.
If there is no 'user' attribute in the request, uses AnonymousUser (from
django.contrib.auth).
"""
# If we access request.user, request.session is accessed, which results in
# 'Vary: Cookie' being sent in every request that uses this context
# processor, which can easily be every request on a site if
# TEMPLATE_CONTEXT_PROCESSORS has this context processor added. This kills
# the ability to cache. So, we carefully ensure these attributes are lazy.
# We don't use django.utils.functional.lazy() for User, because that
# requires knowing the class of the object we want to proxy, which could
# break with custom auth backends. LazyObject is a less complete but more
# flexible solution that is a good enough wrapper for 'User'.
def get_user():
if hasattr(request, 'user'):
return request.user
else:
from django.contrib.auth.models import AnonymousUser
return AnonymousUser()
return {
'user': SimpleLazyObject(get_user),
'messages': messages.get_messages(request),
'perms': lazy(lambda: PermWrapper(get_user()), PermWrapper)(),
}
You can work around the issue by setting context_object_name. For example, this will enable the {{ user_object }} context variable, set to the user of the DetailView:
url(
r'^users/(?P<pk>\d+)/$',
DetailView.as_view(
model = User,
template_name = 'doors/users/detail.html',
context_object_name = 'user_object'
),
name = 'users_detail'
)
Dig deeper, read the documentation for get_context_object_name().

Overriding admin views - Django

I am using Django 1.3 and python 2.7 .I am using Django admin app.What I want is when a superuser logs-in it should be shown admin/index.html with all models which is default behaviour but if any other user logs-in that is not superuser then it should be shown a totally different template with my data (like 'abc.html').What should I do to accomplish this?I guess I need to override some admin view to do this but have no idea?
Please help.If you want more information plz comment :)
I would create a middleware that checks if the user is a superuser or not. If the user is not supeuser you redirects him/her to the custom admin page instead of the default one.
class SuperUserMiddleware(object):
def process_request(self, request):
user = request.session.user
if not user.is_superuser:
return HttpResponseRedirect(NON_SUPERUSER_URL)
...
You create a modified AdminSite class definition with additional permission rules.
class SuperUserAdminSite( AdminSite ):
def has_permission(self, request):
return request.user.is_active and request.user.is_staff and request.user. is_superuser
Now you can create two AdminSite objects, one for ordinary users, one for super users.
You can have two paths in your URLs for the two admin sites.
Superusers can use both paths.
Ordinary users will only be able to use the ordinary user path in the URL.
https://docs.djangoproject.com/en/1.3/ref/contrib/admin/#adminsite-objects
You have to change the view of the admin site. Django Documentation mention all in detail. Please check that https://docs.djangoproject.com/en/1.3/ref/contrib/admin/ if you have any error then please write back with some code details.

Including user statistics for multiple views

I have a navigation bar that displays "login" and "register" when the user is not signed in. When the user is signed in, the navigation bar will display the user's name and the number of messages he has in his inbox.
The problem is that the navigation page is present on around 50 pages, so there are around 50 view functions that have to get the user information and send it to the template. If I want to change this later, it will be a pain!
For example, here is an example view:
def index(request):
user = request.user
...
return render_to_response("page.html", {'user': user})
I have to send the info about the user each time to any page with the navigation bar because my navigation bar contains the code:
{% if user %}
...
{% else %}
....
{% endif %}
Is there a cleaner way to do this?
Edit: Also, I have a UserProfile model which I want to send through to the template. Is there a way to do this, too?
The simplest way is to include django.contrib.auth.context_processors.auth to the TEMPLATE_CONTEXT_PROCESSORS configuration in your settings.py. As described in the docs it wil add a user and perms variable in your template context which gives you direct access to the current user.
Not that the default configuration for TEMPLATE_CONTEXT_PROCESSORS is this (in Django 1.3):
("django.contrib.auth.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.core.context_processors.static",
"django.contrib.messages.context_processors.messages")
So the context processor should already be active und you should be able to access the user variable in you templates without returning it in the view.
In your views, you can simply use the render shortcut which will take care of creating the RequestContext instance that is needed:
from django.shortcuts import render
def my_view(request):
return render(request, 'template.html' )
You could create a custom template tag, as DrTyrsa suggested, or you could create context processor.
You need a custom template tag for that.
Why you need to send user to every view, HttpRequest contains the user, you can easily access it in template when you are logged in.
and another solution is, save the user in sessions, and access it in any view or template.

Categories

Resources