In my "root" template I have something like this
{% if special %}
some_special_html
{% endif %}
The special template var is inserted in template by certain views.
The problem is that I need the password_change view to allso set the special template var.
What's best way to approach this?
Currently, the password_change view is called directly from urls.py:
url(r'^change_password/$', 'django.contrib.auth.views.password_change',
{'template_name': 'profile/password_change.html'},
name='password_change'),
As of at least Django 1.3, the password_change view does take extra context, although the documentation doesn't mention it.
You can pass extra keyword arguments to a view by using the kwargs argument of the url function, so to get the extra context in, do something like this:
url(r'^password/change/$',
auth_views.password_change,
{'template_name': 'profile/password_change.html'},
name='password_change',
kwargs=dict(extra_context={'special': 'special'}),
),
Either move your processing of the special var into a context_processor, or just wrap the password_change auth view with your own view that passes in the correct context.
Related
I have this path in my urls.py:
archive_index_dict = {
'queryset': News.objects.filter(show=True),
'date_field': 'date',
'template_object_name': 'object_list',
}
...
url(r'^$', 'django.views.generic.date_based.archive_index',
archive_index_dict, name='news_archive_index'
),
Now I want to detect in template if a page is current (this is for menu styling). Neither {{ request.path }} nor {{ request.get_full_path }} work in template.
What should I use instead?
SOLUTION
To get request available in templates I had to add django.core.context_processors.request to TEMPLATE_CONTEXT_PROCESSORS. This is not set by default (since django 1.3).
Do you have 'django.core.context_processors.request' context processor set up? Almost all CBV use RequestContext by default
I have a place in my Django app where I need to construct a callback to my domain after a third-party auth, but I'm stuck on how to do this since that view in question doesn't really map to one model (or rather, the view code references multiple models), and the docs for get_absolute_url() construction and permalinks all reference models.
For instance, in my template I currently have something like:
<a class="btn btn-danger large" href="http://to/third/party?api_key=noneyobiz&cb=http://localhost:8000/signup">Join via Somethingorother</a>
the line for this view in urls.py is:
url(r'^signup/$', 'signup', name="signup"),
I want the hardcoded 'http://localhost:8000/signup' to be dynamic. I'm hoping this functionality doesn't depend on my using generic views. Actually I don't understand why generating a permalink is even tied to models at all, it seems like it should only depend on the urlconf. What am I missing here?
permalink is only for the use case when you are referencing a model directly. To find a non-model-based URL, you can use the url tag - in your case, {% url signup %}.
permalink is a thin wrapper of django.core.urlresolvers.reverse. Its belongs to django.db.models to be a shortcut because we usually write reverse inside get_absolute_url of models. So use reverse here
from django.core.urlresolvers import reverse
path = reverse('signup')
Update
To use absolute URI, you could
hardcode in settings or use something like Site.objects.get_current() w/ the path you get from reverse or url to get the absolute URI, as Daniel suggested.
If your callback URI is in the same domain w/ the view rendering the template, you could rely on request to get actual absolute URI:
request.build_absolute_uri(reverse('signup'))
Furthermore, you may want to escape the URI in template, like {{ absolute_uri|urlencode }}. or in view through urllib.quote or urllib.urlencode
In urls.py:
(r'^bbb/id(?P<user_id>[0-9]+)/$', 'django.views.generic.simple.direct_to_template,
{'template': 'some.html', 'extra_context': {'user_id': user_id}}),
In some.html: {{ user_id }}
But there is an error: name 'user_id' is not defined (in urls.py)
So, how to declare that variable in urls.py and send it directly to 'some.html'???
Thanks.
You don't need to put it in extra_context. It's already captured in the URL, so is present in the params dictionary in the template: {{ params.user_id }}.
See the documentation - and also note that these old function-based generic views are deprecated, and you should be using the class-based TemplateView.
The variable really isn't declared in that python code. :) You do not need to set this variable in the view context. The view will receive named matches as **kwargs.
My application uses Django's login view from django.contrib.auth.views.login, with a custom template I made.
I'd like to pass my template an additional argument which will change the login page in a few ways. Actually, I'm trying to show a different login page based on the URL.
How can I pass additional arguments to the login's view & to my custom template?
On Django 1.3 the login view accepts a new extra_context argument in the form of a dictionary.
django/contrib/auth/views.py
def login(request, template_name='registration/login.html',
redirect_field_name=REDIRECT_FIELD_NAME,
authentication_form=AuthenticationForm,
current_app=None, extra_context=None):
To add to Roberto Rosario's answer, you can pass a dictionary of arguments to extra_context inside your urls.py
yourProject/urls.py
from django.conf.urls import url
from django.contrib.auth import views
urlpatterns = [
url(r'^login/$', views.login, {
'template_name': 'your-template-dir/login.html',
'extra_context': {
'additional_arg1': val1,
'additional_arg2': val2,
...
},
}, name="login"),
...
]
Which will then be available in your template.
yourProject/your-template-dir/login.html
{% extends "your-template-dir/base.html" %}
<div>
<p>The value of 'additional_arg1' is {{ additional_arg1 }}.</p>
<p>The value of 'additional_arg2' is {{ additional_arg2 }}.</p>
</div>
Here's Django's official documentation.
The source shows there is only one place that would influence the template context.
def login(request, template_name='registration/login.html',
redirect_field_name=REDIRECT_FIELD_NAME,
authentication_form=AuthenticationForm): # here
So your only option is to hitch a ride on AuthenticationForm or write your own login view (which, by the way, is very simple if you look at the code).
from django.contrib.auth.forms import AuthenticationForm
AuthenticationForm.my_extra_data = 'foobar'
(r'^accounts/login/$', 'django.contrib.auth.views.login', \
{'template_name': 'myapp/login.html', \
'authentication_form': AuthenticationForm }),
Template
{{ form.my_extra_data }}
I was having an heck of time passing extra context variables from my custom login view-function to the template. They were all printing out as the empty string, despite following advice from a number of people a lot smarter than me.
Turns out my urls.py entry was still pointing to the built in login view, not my custom one.
Please don't let this happen to you.
When you eliminate the impossible, whatever remains, however improbable, must be the truth. -- Mr. Spock
{% include 'django.contrib.auth.views.login' %}
I don't want to write everything by hand.. I hate this really, django full of automatic stuff.
Goal is to include registration/login.html into base.html, so that I could have this form in every page
If I include only template itself (registration/login.html), problem appears that "form.login", I mean "form" var is not defined because this one comes from VIEW which called when you going to login url. So how can I call that view MANUALLY with include or at least to grab django.contrib.auth.views.login variables by my self in my own view and pass then to base.html?
P.s. It's not just about login form, I think there will be more situations like this
I have found better solution in #django irc.
They called inclusion tags
I'll give you my code, because I got lot's of problem learning new stuff in django =)
file: templatetags/form_login.py
from django import template
register = template.Library()
from django.contrib.auth.forms import AuthenticationForm
#register.inclusion_tag('registration/login.html')
def form_login():
return { 'form': AuthenticationForm() }
Now you can have your form anywhere, this will prerender template and THAT'S IT! no stupid context processors which requires to modify whole project settings.py, which is really sux if you writing stand alone little application..
If you need login-form on every page
Create a context processor:
def login_form_processor(request):
return {
'login_form': LoginForm(request.POST or None)
}
Add it to settings.CONTEXT_PROCESSORS.
Include the template for login form:
{% with login_form as form %}
{% include "registration/login.html" %}
{% endwith %}
You can also make you form lazy-loading, so form will not be created until it is used for the first time.
from django.utils improt functional
def login_form_processor(request):
create_login_form = lambda: LoginForm(request.POST or None)
return {
'login_form': functional.lazy(create_login_form, LoginForm)
}
But I guess you won't want the lazy-loading feature, because login-form is cheap to initialize.
Reusing views
Concerning the "grabbing variables" part from your question: you cannot grab variable from view. Django view is method which returns response object. You can not get variables from response. However some of views accept extra_context and other attributes. Those attributes allow you to configure those views in urls, or to wrap them with your own view, for example:
def my_login_view(request):
some_extra_data = get_some_data()
extra_context = {
'some_extra_var': some_extra_data
}
return login_view(request, extra_context=extra_context, template="my_template.html")
This is not exactly grabbing the variables from views, more like augmentation of existing views.
If you expect to have more situations like this, do less data-porcessing in views. Call some methods which checks for permissions. Collect some data from context-processors. Return rendered response. Now you can reuse the data in other views.
You can specify the action on the form html to point to the URL that accesses the corresponding view.
If you want a form, say called as login_form always populated in all templates, then put it in the context_processors.
Browsing the code for django.contrib.auth.views, you will see that the variables form, site and *site_name* are passed to the template.
Either you (1) provide your custom registration form or (2) you can just import django.contrib.auth.forms.AuthenticationForm in your view if you want to use it.