User is not being passed to template TEMPLATE_CONTEXT_PROCESSORS - django

Following the docs
If TEMPLATE_CONTEXT_PROCESSORS contains this processor, every
RequestContext will contain these variables:
user – An auth.User instance representing the currently logged-in user
(or an AnonymousUser instance, if the client isn’t logged in). perms –
An instance of django.contrib.auth.context_processors.PermWrapper,
representing the permissions that the currently logged-in user has.
I added these lines to settings.py
TEMPLATE_CONTEXT_PROCESSORS = (
"django.contrib.auth.context_processors.auth",
)
Rendering my templates as follows
def profile_view(request):
return render_to_response('profile.html', { 'profile' : 1 })
I was under the impression that the request context along with the user will be passed automatically. Is that not the case, or should i explicitly add context_instance=template.RequestContext(request)) to every view ?
Thanks.

Yes, if you want to use render_to_response and you want template context data available, you should pass in a RequestContext instance.
Alternatively, if you render your page with django.shortcuts.render, the RequestContext will be injected automatically.
You may find this answer useful, too: Django - what is the difference between render(), render_to_response() and direct_to_template()?

Related

Create a User Profile or other Django Object automatically

I have setup a basic Django site and have added login to the site. Additionally, I have created a Student (Profile) model that expands upon the built in User one. It has a OneToOne relationship with the User Model.
However, I have yet not come right with forcing the user to automatically create a Profile the first time they log in. How would I make sure they are not able to progress through anything without creating this?
I have tried by defining the following in views:
def UserCheck(request):
current_user = request.user
# Check for or create a Student; set default account type here
try:
profile = Student.objects.get(user = request.user)
if profile == None:
return redirect('/student/profile/update')
return True
except:
return redirect('/student/profile/update')
And thereafter adding the following:
UserCheck(request)
at the top of each of my views. This however, never seems to redirect a user to create a profile.
Is there a best way to ensure that the User is forced to create a profile object above?
Looks like you're attempting to do something similar to Django's user_passes_test decorator (documentation). You can turn the function you have into this:
# Side note: Classes are CamelCase, not functions
def user_check(user):
# Simpler way of seeing if the profile exists
profile_exists = Student.objects.filter(user=user).exists()
if profile_exists:
# The user can continue
return True
else:
# If they don't, they need to be sent elsewhere
return False
Then, you can add a decorator to your views:
from django.contrib.auth.decorators import user_passes_test
# Login URL is where they will be sent if user_check returns False
#user_passes_test(user_check, login_url='/student/profile/update')
def some_view(request):
# Do stuff here
pass

How to get the name of current app within a template?

What's the simplest way to access the name of the current app within template code?
Alternatively, what's the simplest way to define a template variable to hold the name of the current app?
(The goal here is to minimize the number of places I need to edit if I rename an app.)
Since Django 1.5 there is a "resolver_match" attribute on the request object.
https://docs.djangoproject.com/en/dev/ref/request-response/
This contains the matched url configuration including "app_name", "namespace", etc.
https://docs.djangoproject.com/en/2.2/ref/urlresolvers/#django.urls.ResolverMatch
The only caveat is that it is not populated until after the first middleware passthrough, so is not available in process_request functions of middleware. However it is available in middleware process_view, views, and context processors. Also, seems like resolver_match is not populated in error handlers.
Example context processor to make available in all templates:
def resolver_context_processor(request):
return {
'app_name': request.resolver_match.app_name,
'namespace': request.resolver_match.namespace,
'url_name': request.resolver_match.url_name
}
There's a way to obtain an app name for a current request.
First, in your project's urls.py, considering your app is called 'main':
#urls.py
url(r'^', include('main.urls', app_name="main")),
Then, a context processsor:
#main/contexts.py
from django.core.urlresolvers import resolve
def appname(request):
return {'appname': resolve(request.path).app_name}
Don't forget to enable it in your settings:
#settings.py
TEMPLATE_CONTEXT_PROCESSORS = (
"django.core.context_processors.request",
"main.contexts.appname",)
You can use it in your template like any other variable: {{ appname }}.

Always send the User information in every Django template

I used a pre-built example templates for Django registration and I noticed that for those pages, Django understands user and I do things like user.is_authenticated and user.username.
I tried looking at the views.py code in both Django registration and the django.contrib.auth.views, but I couldn't figure out how those two always sent the user information to the templates.
I could could always explicitly send the user Context information to every view, but that would be violating the DRY principle.
I tried using this solution, but I get an error saying
Put 'django.contrib.auth.context_processors.auth' in your TEMPLATE_CONTEXT_PROCESSORS setting in order to use the admin application.
And even if I placed the above path inside settings.py like this
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'doors.processor_file_name.user',
)
my templates still doesn't know about user.
It turns out that every time I was using render_to_response in my views.py...
def order_all( request ) :
orders = Order.objects.all()
return render_to_response( 'doors/order/list.html', { 'orders' : orders } )
the dictionary isn't a RequestContext. Using a RequestContext will automatically include the TEMPLATE_CONTEXT_PROCESSORS, which in my case will include django.contrib.auth.context_processors.auth, which will pass along the user information to the every template.
So in other words, I just need to change the code above to this
def order_all( request ) :
orders = Order.objects.all()
return render_to_response( 'doors/order/list.html', context_instance = RequestContext( request, { 'orders' : orders } ) )
Don't forget to import RequestContext too
from django.template import RequestContext
It also turns out I don't need to explicity include django.contrib.auth.context_processors.auth (or write my custom doors.processor_file_name.user) in the TEMPLATE_CONTEXT_PROCESSORS because django.contrib.auth.context_processors.auth is included by default
I realise this is an old question, but for anyone else who runs into this problem, you could use "render", instead of "render_to_response":
def order_all(request):
orders = Order.objects.all()
return render(request, 'doors/order/list.html', { 'orders': order })
This also negates the need to import RequestContext. According to the django docs, "render" is the same as "render_to_response", but has a context instance argument that forces the use of RequestContext.

Django context processor to check user permissions

I would like to write a context processor which will look the existing context, and if there is a form present, check that the user has permission to edit that object. If not, I will overwrite that context variable.
How do I read the existing context from inside a context processor?
Edit:
The reason for using this type of context processor is to avoid having the check permissions with if statements in each view. Some users will have read/write access, others will have read-only and others will have no access, at the object level. I would like to manipulate the form accordingly after the view has been processed.
Why not just wrap the view with a user_passes_test decorator? You can run any checks you like there -- no hacks required.
You should use django-authority, or any authority package. Although, I cannot guarantee that they don't rely on hacks themselves, but at least you wouldn't be alone using the hacks. That said, here is a working solution to your issue:
Monkey patch django.template.base.RequestContext, to set request.context = self.
Create a template context processor, which can use request.context
Add the context processor to settings, and you're good to go
Here is an example, which you can just paste in settings.py, it works:
def print_context(request):
print request.context.get('form', 'No form in this context')
return {}
from django.template.base import RequestContext
orig_init = RequestContext.__init__
def new_init(self, request, **kwargs):
request.context = self
orig_init(self, request, **kwargs)
RequestContext.__init__ = new_init
TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'django.core.context_processors.request',
'settings.print_context',
)
Note that you are working against Django's design, I posted this answer assuming you know what you're doing - you know both Python and Django very well.

How do I pass context to a template without actually specifying it in all views?

I have a few views and they all work good and all use templates that extend one base template that outputs the core HTML, the header, footer, navigation and so on. Happy family.
now, I want to play with sessions on the pages and since you can't get access to user's session information from the template without actually passing it from the view (correct me where I'm wrong) I have two options:
add session data to the rest of the bits I pass as context to HTML templates in views (not sure if this is a good way to go)
somehow inherit all existing views from a view that will be always pushing context to templates being processed - this way I don't have to worry about anything else I may want to add to my pages in the future - is this possible?
I'm very new to django and there may be other proper way of doing this - all your suggestions are much appreciated.
I think adding in a context processor is a very easy way to do this.
You could either write your own or use this one:
DJANGO.CORE.CONTEXT_PROCESSORS.REQUEST
http://docs.djangoproject.com/en/dev/ref/templates/api/#django-core-context-processors-request
Then you will have the request in your template, and could get to the session with request.session
If you do that though, make sure that you pass the RequestContext along in your views to the templates, something like this:
from django.template import RequestContext
def some_view(request):
# ...
return render_to_response('my_template.html',
my_data_dictionary,
context_instance=RequestContext(request))
Also modify your settings.py to add in the context processor
TEMPLATE_CONTEXT_PROCESSORS = DEFAULT_SETTINGS.TEMPLATE_CONTEXT_PROCESSORS + (
"django.core.context_processors.request",
)