I'm trying to use the password reset setup that comes with Django, but the documentation is not very good for it. I'm using Django 1.0 and I keep getting this error:
Caught an exception while rendering: Reverse for 'mysite.django.contrib.auth.views.password_reset_confirm' with arguments '()' and keyword arguments ...
in my urlconf I have something like this:
#django.contrib.auth.views
urlpatterns = patterns('django.contrib.auth.views',
(r'^password_reset/$', 'password_reset', {'template_name': 'accounts/registration/password_reset_form.html', 'email_template_name':'accounts/registration/password_reset_email.html', 'post_reset_redirect':'accounts/login/'}),
(r'^password_reset/done/$', 'password_reset_done', {'template_name': 'accounts/registration/password_reset_done.html'}),
(r'^reset/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$', 'password_reset_confirm', {'template_name': 'accounts/registration/password_reset_confirm.html', 'post_reset_redirect':'accounts/login/', 'post_reset_redirect':'accounts/reset/done/'}),
(r'^reset/done/$', 'password_reset_complete', {'template_name': 'accounts/registration/password_reset_complete.html'}),
)
The problem seems to be in this file:
password_reset_email.html
on line 7
{% url django.contrib.auth.views.password_reset_confirm uidb36=uid, token=token %}
I'm at loss as to what's going on, so any help would be appreciated.
Thanks
Edit: I used your example, and had to change to not use keyword parameters.
{% url django.contrib.auth.views.password_reset_confirm uid, token %}
Named parameters do work, as long as both uid and token are defined. If either are not defined or blank I get the same error you do:
{% url django.contrib.auth.views.password_reset_confirm uidb36=uid, token=token %}
Just wanted to post the solution I came up with. The problem was in this line:
{% url django.contrib.auth.views.password_reset_confirm uidb36=uid, token=token %}
I'm not really a 100% why either, so I just hard coded the url like this:
http://mysite.com/accounts/reset/{{uid}}-{{token}}/
I've struggled with this for over an hour trying everything on this page and every other page on the internet. Finally to solve the problem in my case i had to delete
{% load url from future %}
from the top of my password_reset_email.html template.
Also note, "uidb36=uid" in the url script. Here's my full password_reset_email.html template, I hope it saves someone some time:
{% autoescape off %}
You're receiving this e-mail because you requested a password reset for your user account at {{ site_name }}.
Please go to the following page and choose a new password:
{% block reset_link %}
{{ protocol }}://{{ domain }}{% url django.contrib.auth.views.password_reset_confirm uidb36=uid token=token %}
{% endblock %}
Your username, in case you've forgotten:" %} {{ user.username }}
Thanks for using our site!
The {{ site_name }} team
{% endautoescape %}
This is a problem I figured out myself not 10 minutes ago. The solution is to add the post_change_redirect value to the dictionary of arguments you are passing to the password_reset view.
So this is what mine now look like:
(r'^/password/$', password_change, {'template_name': 'testing/password.html', 'post_change_redirect': '/account/'})
I hope that does it for you! I agree that the documentation for this particular feature is lacking somewhat, but this solved the exact same issue for my project.
Edit: I really should have scrolled across - you've included that already. Apologies for that, but I hope you get it sorted :)
Related
I am follwing the exact steps in this blog.
also made the changes:
1) the url template tag syntax as noted above by "F L"
2) uidb36 in the urls.py and email template both should be uidb64 per https://docs.djangoproject.com/en/1.6/releases/1.6/#django-contrib-auth-password-reset-uses-base-64-encoding-of-user-pk
When I enter the email address, I get the mail and after entering the url: http://localhost:8000/user/password/reset/NDI-47h-e1fbd1df48ce2aa05de4/, I always get the message:
Password reset unsuccessful
The password reset link was invalid,
possibly because it has already been used.
Please request a new password reset.
i.e the validlink always fails. Why?
Sharing relevant Code blocks: urls.py:
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
url(r'^user/password/reset/$',
'django.contrib.auth.views.password_reset',
{'post_reset_redirect' : '/user/password/reset/done/'}, name="password_reset"),
(r'^user/password/reset/done/$',
'django.contrib.auth.views.password_reset_done'),
(r'^user/password/reset/(?P<uidb64>[0-9A-Za-z_\-]+)-(?P<token>.+)/$',
'django.contrib.auth.views.password_reset_confirm',
{'post_reset_redirect' : '/user/password/done/'}),
(r'^user/password/done/$',
'django.contrib.auth.views.password_reset_complete'),
In my template folder, created a folder called registration: The structure of my template folder:
/templates$ find
.
./registration
./registration/password_reset_form.html
./registration/password_reset_confirm.html
./registration/password_reset_email.html
./registration/password_reset_done.html
./registration/password_reset_complete.html
./admin
password_reset_email.html:
{% load i18n %}
{% comment %}
{% load url from future %}
{% endcomment %}
{% autoescape off %}
You're receiving this e-mail because you requested a password reset for your user account at {{ site_name }}.
Please go to the following page and choose a new password:
{% block reset_link %}
{{ 'http' }}://{{ 'localhost:8000' }}{% url 'django.contrib.auth.views.password_reset_confirm' uidb64=uid token=token %}
{% endblock %}
Your username, in case you've forgotten: {{ user.username }}
Thanks for using our site!
The {{ site_name }} team.
All other templates as in the blog
I'm guessing the - in your URL is a problem because your first regular expression group matches -'s greedily.
Notice that - is matched by that first regular expression but you're also using it as a delimiter.
Instead of this URL pattern:
r'^user/password/reset/(?P<uidb64>[0-9A-Za-z_\-]+)-(?P<token>.+)/$'
Try this one:
r'^user/password/reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>.+)/$'
The difference is that we changed the - in between the matching groups to a /, which is a character not matched within the first group.
I'm using django flatpages, and I'm wondering if there is a concise way of loading one specific flatpage within a template. The docs show the following patterns:
{% load flatpages %}
{% get_flatpages '/about/' as about_pages %}
{% get_flatpages about_prefix as about_pages %}
{% get_flatpages '/about/' for someuser as about_pages %}
I just want to load one specific page in a template, essentially using it like an include statement (e.g. {% include 'homepage.html' %})
The approach I am using is this:
{% get_flatpages '/flat-homepage/' as flatpages %}
{{ flatpages.first.content|safe }}
This works fine, but I thought there might be a slightly neater way of doing this. I'm marking the content as safe as I want html styles to be applied (again, not sure if there is a better way of doing this)
By default, there are 2 solutions for that.
First, register your flatpage in urls as below:
from django.contrib.flatpages import views
urlpatterns = [
url(r'^about-us/$', views.flatpage, {'url': '/about-us/'}, name='about'),
]
That way, you can access it using {% url %} tag, like normal view.
Second way, if you know exact url of that page, you can access it's url using:
{% url 'django.contrib.flatpages.views.flatpage' url='url_to_flatpage_here' %}
There is no other way, because all flatpages are identified by url.
I have set the following entry in the urls.py
(r'^password_reset/$', 'django.contrib.auth.views.password_reset'),
but once I go to http://127.0.0.1:8000/password_reset/ I get the error message:
NoReverseMatch at /password_reset/
Reverse for 'django.contrib.auth.views.password_reset_done' with arguments '()' and keyword arguments '{}' not found.
I was expecting password_reset_done view also to be coming out of the box. So what am I supposed to do at this stage?
UPDATE
After trying Blair's solution, I got a step closer.
(r'^password_reset_done/$', 'django.contrib.auth.views.password_reset_done'),
According to the book 'Django 1.0 Website Development', these built-in views should be used out of the box without further hassle. But maybe it has changed since Django 1.0...
Would be great if someone could shed light on this. Thanks
I have finally found the solution. I think there is always the slight misunderstanding between MVC and MTV pattern. In MTV (Django) the View stands for the controller and the Template stands for the View.
Hence while its true that the change password "Views" are coming built-in out-of-the-box, the actual templates (look & feel) still needs to be generated by the user while the underlying form (widget) is generated by Django automatically. It gets more clear when looking at the code.
Therefore add these two lines to url.py
(r'^change-password/$', 'django.contrib.auth.views.password_change'),
(r'^password-changed/$', 'django.contrib.auth.views.password_change_done'),
Then Under myproject/templates/registration add these two files
password_change_done.html
{% extends "base.html" %}
{% block title %}Password Change Successful{% endblock %}
{% block head %}Password Change Completed Successfully{% endblock %}
{% block content %}
Your password has been changed successfully. Please re-login with your new credentials
login or go back to the
main page.
{% endblock %}
password_change_form.html
{% extends "base.html" %}
{% block title %}Change Registration{% endblock %}
{% block head %}Change Registration{% endblock %}
{% block content %}
<form method="post" action=".">
{{form.as_p}}
<input type="submit" value="Change" />
{% csrf_token %}
</form>
{% endblock %}
Django needs to know which URL to redirect the user to once they have completed the form on the password_reset page. So add another line to your URL configuration:
(r'^password_reset_done/$', 'django.contrib.auth.views.password_reset_done'),
As of django 1.11 password_change view is deprecated.
Deprecated since version 1.11: The password_change function-based view should be replaced by the class-based PasswordChangeView.
What worked for me was:
In urls.py
from django.contrib.auth import views as auth_views
...
url('^account/change-password/$',
auth_views.PasswordChangeView.as_view(
template_name='registration/passwd_change_form.html'),
name='password_change'),
url(r'^account/password-change-done/$',
auth_views.PasswordChangeDoneView.as_view(
template_name='registration/passwd_change_done.html'),
name='password_change_done'),
And then add the couple of templates passwd_change_form.html and passwd_change_done.html under registration.
Note that I'm not using the default name, for some reason when I did that it defaulted to the django admin views.
I have the following code in my template:
{% for req in user.requests_made_set.all %}
{% if not req.is_published %}
{{ req }}
{% endif %}
{% empty %}
No requests
{% endfor %}
If there are some requests but none has the is_published = True then how could I output a message (like "No requests") ?? I'd only like to use Django templates and not do it in my view!
Thanks
Even if this might be possible to achieve in the template, I (and probably many other people) would advise against it. To achieve this, you basically need to find out whether there are any objects in the database matching some criteria. That is certainly not something that belongs into a template.
Templates are intended to be used to define how stuff is displayed. The task you're solving is determining what stuff to display. This definitely belongs in a view and not a template.
If you want to avoid placing it in a view just because you want the information to appear on each page, regardless of the view, consider using a context processor which would add the required information to your template context automatically, or writing a template tag that would solve this for you.
I have a form that redirects to the same page after a user enters information (so that they can continue entering information). If the form submission is successful, I'm returning
HttpResponseRedirect(request.path)
which works fine. However, I'd also like to display some messages to the user in this case (e.g., "Your data has been saved" at the top of the screen). If I weren't redirecting, I'd just return these messages in the context dictionary. With the redirect, however, I can't do this.
So how can I pass template context information when using HttpResponseRedirect?
What I'm trying to do seems like it would be incredibly common, so please excuse me if I'm missing something obvious.
For the sake of completion and future reference, you can now use the messages framework. After you install it:
views.py
from django.contrib import messages
def view(request):
# your code
messages.success(request, "Your data has been saved!")
HttpResponseRedirect(request.path)
template.html
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
if you are using auth and have a logged in user you could:
http://docs.djangoproject.com/en/dev/topics/auth/#django.contrib.auth.models.User.message_set.create
GET params are also hackable. The querystring, as mentioned in other answers, could be used.
I think the most preferred way would be to use the sessions framework. That way you can load up whatever you want in the context and get
{{ request.session.foo }}
foo could be the message or you could do:
{% ifequal request.session.foo 1 %} Nice work! {% else %} Almost! {% endifequal %}
and other fun stuff.
http://docs.djangoproject.com/en/dev/topics/http/sessions/#using-sessions-in-views
You can't. HttpResponseRedirect sends a client-side redirect (HTTP status code 302) to the browser, and then the browser re-requests another page.
You can set a URL query string on the redirect, though that will be visible to the user and anyone intercepting HTTP requests (i.e. proxies), and is therefore not suitable for sensitive information.
The best way would probably be to use a coded querystring on the redirect URL... its an old school approach.
You could do something like
/page/?m=1, /page/?m=2, etc
You would then parse that variable with request.GET in the view code and show the appropriate message.
From your views.py you hast have to put a key/value-pair into the session and then read it from the HTML template.
For example:
views.py
# your code here
request.session['vote'] = 1
return HttpResponseRedirect(request.path)
your_template.html
{% ifequal request.session.vote 1 %}
<!-- Your action here -->
{% endifequal %}
The only way I know of to pass any data with a redirect is to add GET parameters to the URL you're passing in. To avoid XSS hacks you'd want to pass a specific constant like:
[current path you're passing in]?message=saved
And then process the message=saved parameter in the handler for the path you passed in.
A somewhat more complicated way would be not passing the data in the redirect, and instead using something like http://code.google.com/p/django-notify/ to store session-based data that is displayed to the user following the redirect.
You add ?saved=1 to the query string and check for it with something like:
saved = request.GET.get('saved', False)