I understand things have changed in Django 1.8 with how render_to_response
takes arguments. I have lots of views and use this pattern everywhere:
...return render_to_response( template, context,
context_instance=MyRequestContext(request))
MyRequestContext extends the RequestContext and adds some paramaters I always use in my templates.
Now this no longer works, and values in MyRequestContext is no longer accessible in the templates anymore.
So how should RequestContext be use now in Django 1.8? I need them + some context passed to all my templates.
/ J
-- EDIT --
Thanks for all the answers, as you point out this should work...
I ended up rewriting and replacing my previous subclassing of RequestContext --> MyRequestContext w. doing a separate ContextProcessors function and adding this into my OPTIONS:context_processors list and then using a normal RequestContext(request) in all of my views. Not sure what bug/problem I had in old solutions but this works now. Again - thanks for inspiration and responses.
You can manually fetch the template and render it to a HttpResponse object:
from django.template.loader import get_template
from django.http import HttpResponse
template = get_template(template_name)
context = MyRequestContext(request, context_dict)
return HttpResponse(template.render(context))
I bumped into this as well and had to read the docs on render_to_response a couple of times.
The thing that confused me is the example code in combination with the deprecation warning:
return render_to_response('my_template.html',
my_context,
context_instance=RequestContext(request))
Deprecated since version 1.8: The context_instance argument is
deprecated. Simply use context.
Note that context_instance is still used at many examples in the documentation and it is okay to use it that way until Django 2. I don't want to wait until I'm forced to change when I upgrade so...
I moved my_context dict out of render_to_response into the RequestContext class. I believe this must be the new style:
return render_to_response('template.html',
context=RequestContext(request, my_context))
Context is the second argument, so you don't even have to name it:
return render_to_response('template.html',
RequestContext(request, my_context))
Related
Why does Django need a request object in rendering a template?
return render(request, 'polls/index.html', context)
As per the docs about render:
Combines a given template with a given context dictionary and returns
an HttpResponse object with that rendered text.
Thus it's meant to be used in views, where you have a request object and need to return an HttpResponse. A typical use case is when you build the context from the request.
If you only need to render a template, you can use the shortcut function render_to_string:
from django.template.loader import render_to_string
render_to_string('your_template.html', {'some_key':'some_value'})
Or do it manually:
from django.template import Context, Template
Template('your_template.html').render(Context({'some_key':'some_value'})
The request argument is used if you want to use a RequestContext which is usually the case when you want to use template context processors. You can pass in None as the request argument if you want and you will get a regular Context object in your template.
I believe this is b/c the render() shortcut is using a RequestContext
You could also use get_template directly and call render with a normal Context
I need to get an environment variable (ex: Mixpanel_Token) in all my templates, and without creating a new view in Django.
From what I read on SO, I should use a Template Context Processor.
The context_processor is defined in context_processors.py file:
from django.conf import settings
def settings_mixpanel(request):
ctx = {
"MIXPANEL_TOKEN": settings.MIXPANEL_TOKEN,
}
return ctx
In my settings.py file:
TEMPLATE_CONTEXT_PROCESSORS = (
'utils.context_processors.settings_mixpanel',
)
The issue I encounter is how to define MIXPANEL_TOKEN as a context variable in all my templates, given that all my views are already created in Django.
I don't want to recreate a view like the below one, using render_to_response function:
def index(request):
return render_to_response("index.html", {},context_instance=RequestContext(request))
You don't need to do anything special. As long as your template is rendered with RequestContext, you'll be able to access your variable with {{ MIXPANEL_TOKEN }}.
It is quite easy and straightforward: the context processors are called by RequestContext(...). If you do not use RequestContext(...), the context processors will not be used and will therefore not be of any value. You do not necessarily need to use render_to_response, but RequestContext is a must. Like it or not, that is how Django works. But from my personal view, changing your existing views to use RequestContext is not really a big thing, is it?
since Django 1.8 registring of custom context processor for templates happens via: TEMPLATES-> OPTIONS -> context_processors see here for reference: https://docs.djangoproject.com/en/1.10/ref/templates/upgrading/#the-templates-settings
In django/contrib/auth/views.py there is the definition of the logout view :
def logout(request, next_page=None,
template_name='registration/logged_out.html',
redirect_field_name=REDIRECT_FIELD_NAME,
current_app=None, extra_context=None):
I would like to add extra_context to get rid of the 'Logged out' title that appear when I log off
so I'm trying this in my url confs :
(r'^accounts/logout/$', logout(extra_context={'title':'something else'}) ),
but then I get this error : logout() takes at least 1 non-keyword argument (0 given)
what I'm doing wrong?
ps:
when I do
(r'^accounts/logout/$', logout ),
it works, but then I get the 'Logged out' text...
Thanks,
Fred
When you write logout(extra_context={'title':'something else'}), you're actually calling logout right there in the URLconf, which won't work. Any URLconf tuple can have an optional third element, which should be a dictionary of extra keyword arguments to pass to the view function.
(r'^accounts/logout/$', logout, {'extra_context':{'title':'something else'}}),
Alternatively, you could write your own view which calls logout passing in whatever arguments you want -- that's typically how you would "extend" function-based generic views in more complicated cases.
Adding my findings for django 2.0 as the previous answer on this thread no longer works for the most recent django version.
With 2.0, the proper way of adding a URL to your urls.py file is by using path():
from django.urls import path
from django.contrib.auth import views as auth_views
path('accounts/logout/', auth_views.LogoutView.as_view(
extra_context={'foo':'bar'}
)),
The code snippet to highlight here is the .as_view() function. Django 2.0 implements auth views as classes. You can read more about this in the Authentication Views documentation
You then "convert" the class to a view using `.as_view() and you are able to pass in any class attributes defined in the source code as named parameters.
Passing in extra_context (which defaults to None) automatically exposes these context variables to your templates.
You can access the source code for LogoutView by following this python path: django.contrib.auth.views
Here you can see the other class attributes you can pass into LogoutView and the other auth view classes.
I had a similar problem with titles and generic views in django 1.11 (though the problem was mostly that I didn't switch docs version from 2.0). I wanted to pass title via extra_context to the view inherited from CreateView, and discovered that django's generic view had no such attribute. So, here are my crutches:
Create custom mixin (hope that's more or less what ContextMixin in 2.0 does):
class ExtraContextMixin():
extra_context = {}
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update(self.extra_context)
return context
Add mixin to view's ancestors (that's all code I had to change):
class CustomView(ExtraContextMixin, CreateView):
Pass extra_context from url:
url(r'^custom-view/$', views.CustomView.as_view(extra_context={'title': 'just any'}), name='custom-view')
Unfortunately, I have no idea whether such solution is acceptable (no need since 2.0, obviously), but at least it's working.
I'm putting
...}, context_instance=RequestContext(request))
at the end of all my render_to_response's. I'm sure this is not right. Can anyone tell me when I should be using these?
If you are using Django 1.3 you can use the render() shortcut function so you don't have to explicitly write context_instance=RequestContext(request) for each view .
Combines a given template with a given
context dictionary and returns an
HttpResponse object with that rendered
text.
render() is the same as a call to
render_to_response() with a
context_instance argument that forces
the use of a RequestContext.
You are doing it "right". This means that all of the Context Processors will run on this view, and you will have access to all of the juicy bits in your template.
The other way to do this is to use direct_to_template, which saves you having to instantiate a RequestContext object, but has the same outcomes.
so I was wondering if you could return an inclusion tag directly from a view.
The page is a normal page with a list of items. The list of items is rendered using an inclusion tag. If an ajax request is made to the view, I want to return only what the inclusion tag would return so I can append it onto the page via javascript. Is something like this possible? Or should I architect this better?
This sounds like a job for the render_to_string or render_to_response shortcuts:
https://docs.djangoproject.com/en/dev/ref/templates/api/#the-render-to-string-shortcut
https://docs.djangoproject.com/en/dev/topics/http/shortcuts/#django.shortcuts.render_to_response
We can still use the inclusion tag to generate a template context dict from our args (as helpfully pointed out by #BobStein-VisiBone in comments)
from django.template.loader import render_to_string
from django.shortcuts import render_to_response
from .templatetags import my_inclusion_tag
rendered = render_to_string('my_include.html', my_inclusion_tag(foo='bar'))
#or
def my_view(request):
if request.is_ajax():
return render_to_response('my_include.html',
my_inclusion_tag(foo='bar'),
context_instance=RequestContext(request))
quick and dirty way could be to have a view, that renders a template, that only contains your templatetag.
I was trying to do the exact same thing today, and ended up writing a helper function to render template tags:
def render_templatetag(request, tag_string, tag_file, dictionary=None):
dictionary = dictionary or {}
context_instance = RequestContext(request)
context_instance.update(dictionary)
t = Template("{%% load %s %%}{%% %s %%}" % (tag_file, tag_string))
return t.render(context_instance)
tag_string is the call to the template tag as it'd appear in a normal template, and tag_file is the file you need to load for the template tag.
This is certainly possible. A view can render any template that an inclusion tag can. The advantage of this approach is that you can leverage the full strength of Django's templates.
On the other hand AJAX responses typically do not contain HTML so much as XML/JSON. If you are using Django's template features you are better off with returning HTML. If not, XML/JSON might make more sense. Just my two cents.
Using inclusion tag with configurable template decorator provided by Gonz instead of default Django's inclusion tags you can write a helper in your view:
from django.template.loader import render_to_string
from home.templatetags.objectwidgets import object_widget
def _object_widget(request, obj):
template, context = object_widget(RequestContext(request), obj)
return render_to_string(template, context)
It's DRY and works with Django 1.3 (I haven't tested it with Django 1.4).
I use this technique to return search results rendered in HTML via JSON/AJAX calls (nothing better which I came up with).
It's possible, but probably bit hacky, complex or complicated.
What I would suggest, is architect it so that you have the rendering part in utils.py function and use it in a simple_tag instead of an inclusion_tag. This way you can then use the same utils rendering function easily in views.
In my (very simplified) imaginary example I have listing of users and a "Load more" button that returns more users.
account/utils.py
from django.template.loader import render_to_string
def render_users(users):
return render_to_string("account/user_list_items.html", {"users": users})
account/templatetags/account_tags.py
from django import template
from ..utils import render_users
register = template.Library()
#register.simple_tag
def list_users(users):
return render_users(users)
account/views.py
from django.http import HttpResponse
from .models import User
from .utils import render_users
def load_more_users(request):
limit = request.GET["limit"]
offset = request.GET["offset"]
users = User.objects.all()[offset:offset + limit]
return HttpResponse(render_users(users))
Simple is better than complex.