Django password_change view & PasswordChangeForm not working - django

I'm trying to get password_change view and PasswordChangeForm working, but I get an html where the form renders correctly but nothing happens when I fill the form and click enter and there isn't a "send" button for the form. I'm probably missing something simple here, but the docs doesn't seem very helpful.
So, this is the urls.py:
from django.contrib.auth.views import password_change
from sisacademico import views
url(r'^password_changed/$', views.password_changed, name='password_changed'),
url(r'^change_password/$', password_change,
{'template_name': 'sisacademico/change_password.html',
'post_change_redirect': sisacademico/password_changed/'}),
this is the html, change_password.html:
{% extends 'base_sisacademico.html' %}
{% block content %}
{{form.as_ul}}
{% endblock content %}
What I get is this form with no submit button that doesn't work:

The Django template form tags {{ form }} don't output a submit button. You're going to need to put that in your HTML. You'll have something like:
<form method="post">
{% csrf_token %}
{{ form.as_ul }}
<input type="submit" value="Submit" />
</form>
take a look at the form docs for other examples

Related

Django Template Second Form Input Triggering Wrong View

Trying to have two forms on one page and have a user select a create input or load input. Should be pretty straight forward. Doesn't seem to work. Anytime I click select a person and click load, it evaluates the first URL for Create. Can someone please point out what I'm missing? I'm sure it's something simple.
Views:
def Create(request):
print('Create View')
def Load(request):
print('Load View')
URLs:
urlpatterns = [
path('', views.Index, name='index'),
path('person/', views.Create, name='Create'),
path('person/', views.Load, name='Load'),
Template:
{% block body_main %}
<form action={% url 'Create' %} method='POST'>
<h2>Name</h2>
{% csrf_token %}
{{ form1 }}
<input class="btn btn-success" name="form1btn" value="Submit" type="submit"/>
</form>
<br>
<form action={% url 'Load' %} method='POST'>
<h2>Select Existing Name</h2>
{% csrf_token %}
{{ form2 }}
<input class="btn btn-success" name="form2btn" value="Submit" type="submit"/>
<form>
{% endblock %}
Here is the problem (also mentioned in point 3 in Django URL docs:
path('person/', views.Create, name='Create'),
path('person/', views.Load, name='Load'),
Everytime django URL matcher gets here, it will usually hit Create first and return.
Django runs through each URL pattern, in order, and stops at the first one that matches the requested URL, matching against path_info.
So it will always return the Create view.
To solve this problem I suggest creating 3 separate URLs that are more readable:
path('person/new', views.Create, name='Create'),
path('person/load', views.Load, name='Load'),

Why I can't save the edit of a Django ModelForm blog?

I was doing the Python Crash Course Ex. 19-1: Blogs, and I'm now stuck at saving the edit of any blog. I tried plugging in the .errors code in the blog.html (for showing each blog) but it shows nothing, so I guess my templates has no field errors (?)
Here're some codes I believe crucial for solving the not-saving-the-edit problem. The new_blog function in views.py works fine so I'll skip it.
The edit_blog function in views.py:
def edit_blog(request, blog_id):
idk = BlogPost.objects.get(id = blog_id)
if request.method != "POST":
form = BlogForm(instance = idk)
else:
form = BlogForm(instance = idk, data = request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('blogs:blogs'))
content = {"editing_blog": form, "psst": idk}
return render(request, 'blogs/edit_blog.html', content)
new_blog.html:
{% extends "blogs/all.html" %}
{% block content %}
<p>Write a new blog:</p>
<form action="{% url 'blogs:new_blog' %}" method='post'>
{% csrf_token %}
<table border="1">
{{ new_blog }}
</table>
<p></p>
<button name="submit">Submit</button>
</form>
{% endblock content %}
edit_blog.html:
{% extends "blogs/all.html" %}
{% block content %}
<p>Edit the blog:</p>
<form action="{% url 'blogs:blog' psst.id %}" method='post'>
{% csrf_token %}
<table border="1">
{{ editing_blog }}
</table>
<p></p>
<button name="submit">Save changes</button>
</form>
{% endblock content %}
Btw, the urlpattern is here:
from django.urls import path, include
from . import views
app_name = 'blogs'
urlpatterns = [
# Home page
path('', views.homepage, name = 'homepage'),
# Show all blogs.
path('blogs/', views.blogs, name = 'blogs'),
# Show the detail of a blog.
path('blogs/<int:blog_id>', views.blog, name = 'blog'),
# Page for adding a new blog.
path('new_blog/', views.new_blog, name = 'new_blog'),
# Page for editing a blog.
path('edit_blog/<int:blog_id>', views.edit_blog, name = 'edit_blog'),
]
No matter how I change the title, or content, or both of the blog I don't see the changes saved. Is it:
A) My form action in edit_blog.html goes wrong, as wakandan mentioned?
B) I need to adjust something in edit_blog view function, like Bibhas said?
Many thanks. Also tell me if I need to add more codes for understanding.
Your form action is currently set to {% url 'blogs:blog' psst.id %}, which means you're posting to your views.blog view, which is just a detail view. You need to change the action to {% url 'blogs:edit_blog' psst.id %} so that the form is posted to your edit view.
It's not clear from the code you have posted where the editing_blog context variable is coming from - you will need to make sure that this is an instance of the same form that your edit view is looking for, otherwise you'll run into other problems.
Finally also note that you are not currently handling the case where the form has errors - i.e., there is no else condition specified for form.is_valid().

Trouble with Django Logout Page, django-registration logout.html Template Form Fields

I am using django-registration. After getting it working, I went on extending views and forms for field customization using Bootstrap.
I have this working for everything except the logout page. In the default method, I simply built the form by scratch and it worked OK. But when trying to use Django's forms, it's not showing the fields at all. Both the login and logout templates use this basic form:
<div class="auth-form">
<form class="form-signin" method="post" action="/accounts/login/">
{% csrf_token %}
<h2 class="form-signin-heading">Please log in</h2>
<div class="font-16px top-mar-1em">
<label for="id_username"></label>
{{ form.username }}
<label for="id_password1"></label>
{{ form.password }}
<div class="form-group">
<div class="col-sm-10">
<div class="level-checkbox">
<label for="checkbox">
{{ form.remember_me }} Remember me
</label>
</div>
</div>
</div>
<button class="btn btn-primary" type="submit">Log in</button>
</div>
</form>
</div>
This works fine for the login page, but for the logout page it doesn't (the fields are missing). It's like the form is not available to this page. I'm sure I missed something simple but I can't figure it out.
My urls.py section look like this:
url(r'^accounts/login/$','django.contrib.auth.views.login', {
'template_name': 'registration/login.html',
'authentication_form': UserAuthenticationForm,
}),
I've tried adding a logout section to urls.py similar to the login one, but that hasn't worked. I've tried using logout_then_login, using login.html as import template on logout.html and other miscellaneous things to no avail.
Apparently, there is no form associated with the default logout view, so this is probably the issue but I'm not sure the best way to implement a standard form in the logout view.
You should be able to add the following to your urls.py and have everything work.
url(r'^accounts/logout/$','django.contrib.auth.views.logout_then_login')
Make sure you have LOGIN_URL defined your settings.py. Then when a user clicks a logout link they will hit the logout view which takes care of redirecting to the login view which contains your form.
Thanks to #tsurantino I was able to get this working using the messages framework. I always like when I have to implement a new feature using a part of Django I haven't used before. Adding to the toolkit, so to speak. Here is what I did:
Since I had a signal_connectors.py file already for sending email based on user registration/activation I just added to it:
#receiver(user_logged_out)
def user_logged_out_message(sender, request, **kwargs):
messages.add_message(
request,
messages.INFO,
'You\'ve been successfully logged out. You can log in again below.'
)
Then in my common app's __init__.py I imported it:
from common.signal_connectors import user_logged_out_message
Then in my login.html template:
{% if messages %}
<div class="alert-success align-ctr font-16px top-mar-2em">
{% for message in messages %}
{{ message }}
{% endfor %}
</div>
{% endif %}
Finally, to redirect to login page after logout (urls.py):
url(r'^accounts/logout/$','django.contrib.auth.views.logout_then_login'),
Thanks for everyone’s help and comments.

Django register and login - explained by example

Can someone please explain in details how to make a registration and authentication in as easy words as possible ? I made authentication (login) with django.contrib.auth but what I want to get is a full register(social/non)+login. Already saw the django-allauth, django-social-auth, django-social but still can't get it working without hacking a lot. Heard that django-registration and django-profiles can make it a lot easier, but i can't handle it. For example,
~/.virtualenvs/plinter/lib/python2.7/site-packages/registration/backends/default/urls.py
needs a small hack to work:
# from django.views.generic.simple import direct_to_template
from django.views.generic import RedirectView
...
RedirectView.as_view(url='/registration/activation_complete.html'),
# direct_to_template,
# {'template': 'registration/activation_complete.html'},
...
The DjangoBook gives simple examples of Contact and search forms. But i can't expand it on user registration and login.
So can anyone give kis example of working registration and login?
Update
Here is a simple example of login. Now django-allauth or social auth or registration2 are in consideration...
Update2
django-allauth seems to be the best solution for easier authentication. Add correctly apps in settings, register fb/google/etc apps and register through admin and use template inheritance to change default pages design.
THIS is a very good tutorial about login & Co. It explains very well how to perform login by ourself ad override existing django login pages.
UPDATE:
Here Overview for Registration and Login. For more details go to the link.
To Register:
Views and URLs
Go to the lower site folder (where the settings.py file is) and open
the views.py file. At the top make sure the following imports are
included. Add them if not:
from django.shortcuts import
render_to_response from django.http import HttpResponseRedirect from
django.contrib.auth.forms import UserCreationForm from
django.core.context_processors import csrf
Below that add the following functions (you can put them after the
Login functions):
def
register(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/accounts/register/complete')
else:
form = UserCreationForm()
token = {}
token.update(csrf(request))
token['form'] = form
return render_to_response('registration/registration_form.html', token)
def registration_complete(request):
return render_to_response('registration/registration_complete.html')
Open the urls.py file in the site folder (same folder as
settings.py). Below urlpatterns = patterns('', insert the following
lines.
# Registration URLs
url(r'^accounts/register/$', 'simplesite.views.register', name='register'),
url(r'^accounts/register/complete/$', 'simplesite.views.registration_complete',
name='registration_complete'),
Templates We will assume your site already has a templates
directory and a base.html file with the navigation bar. Open the
base.html file and in the nav element add a navigation menu link to
the login page
register
If one does not already exist, go to the templates folder and create
a folder inside it named registration. Create a file called
registration_form.html, save it to the templates/registration folder,
then populate it with the following:
{% extends "base.html" %} {% block title %}Register{%
endblock %} {% block content %}
<h2>Registration</h2>
<form action="/accounts/register/" method="post">{% csrf_token %}
{{form.as_p}} <input type="submit" value="Register" />
</form>
{% endblock %}
Create a file called registration_complete.html, save it to the
templates/registration folder, and populate it with the following:
{% extends "base.html" %} {% block title %}You are
Registered{% endblock %} {% block content %}
<h2>Thank you for Registering</h2> <p>Please Login</p>
{% endblock %}
To Login:
Views and URLs Open the views.py file in the lower site folder (where the settings.py file is). If there isn't one then create and
save it. At the top of the file insert the following import: from
django.shortcuts import render_to_response Below that you only need to
add one function rendering the loggedin page. The other functions
(login and logout) are in the views.py file in the Django Auth folder.
def loggedin(request):
return render_to_response('registration/loggedin.html')
# Optionally, if you want to show their username when they login then call their username in the view. Change the loggedin function to:
def loggedin(request):
return render_to_response('registration/loggedin.html',
{'username': request.user.username})
Open the urls.py file in the site folder (same folder as settings.py).
Below urlpatterns = patterns('', insert the following lines.
# Auth-related URLs:
url(r'^accounts/login/$', 'django.contrib.auth.views.login', name='login'),
url(r'^accounts/logout/$', 'django.contrib.auth.views.logout', name='logout'),
url(r'^accounts/loggedin/$', 'simplesite.views.loggedin', name='loggedin'),
With simplesite being the name of the folder that holds the views.py
file that you are calling. Open the settings.py file and at the bottom
insert LOGIN_REDIRECT_URL = '/accounts/loggedin/'. Django's default
is to redirect to /accounts/profile when you log in, which is fine if
you have an profile page at that url. If not you need to change your
settings default for the Login redirect url to the one holding your
loggedin.html page.
Templates
We will assume your site already has a templates directory and a
base.html file with the navigation bar. Open the base.html file and in
the nav element add a navigation menu link to the login page login Add a logout link too logout Create a directory called
registration inside the templates folder. If you do this through the
command line, type mkdir registration Create a file called login.html,
save it to the templates/registration folder, and populate it with the
following:
{% extends "base.html" %}
{% block title %}Log In{% endblock %}
{% block content %}
<form method="post" action="{% url 'django.contrib.auth.views.login' %}">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<input type="submit" value="login" />
</form>
{% endblock %}
{{ form.as_table }} uses the Django Forms module to create the form.
You can create an unformatted form by using {{ form }} without the
HTML table tags, or have each field put inside paragraph tags with {{
form.as_p }}, or as an unordered list {{ form.as_ul }}. Optionally, you
can also lay out your own form structure and use the form field tags
as follows:
{% extends "base.html" %}
{% block title %}Log In{% endblock %}
{% block content %}
<form method="post" action="{% url 'django.contrib.auth.views.login' %}">
{% csrf_token %}
{% if form.errors %}
<p>Your Username or Password were not entered correctly. Please try again.</p>
{% endif %}
<table>
<tr>
<td>{{ form.username.label_tag }}</td>
<td>{{ form.username }}</td>
<td>{{ form.username.errors }}</td>
</tr>
<tr>
<td>{{ form.password.label_tag }}</td>
<td>{{ form.password }}</td>
<td>{{ form.password.errors }}</td>
</tr>
</table>
<input type="submit" value="login" />
</form>
{% endblock %}
Create a file called loggedin.html, save it to the
templates/registration folder, and populate it with the following:
{% extends "base.html" %}
{% block title %}Logged In{% endblock %}
{% block content %}
<h2>You are logged in</h2>
{% endblock %}
If you want to display the username, you would make the adjustment to
the view discussed in the views section. Then change the loggedin.html
template to the below (change the wording as you see fit):
{% extends "base.html" %}
{% block title %}Logged In{% endblock %}
{% block content %}
<h1>Welcome {{username}}</h1>
<p>Thank you for logging in.</p>
<p>Logout</p>
{% endblock %}
Create a file called logged_out.html, save it to the
templates/registration folder and populate it with the following:
{% extends "base.html" %}
{% block title %}Logged Out{% endblock %}
{% block content %}
<h2>Logged out!</h2>
<p>Log back in</p>
{% endblock %}
Trix's approach worked for me, but the logout link was redirecting to the admin logout, instead of logged_out.html.
To fix the redirect, I added a next option to the href:
Logout
In templates/registration:
Renamed logged_out.html to loggedout.html; the underscore caused it to still route to the admin logout page.
In views.py:
def loggedout(request):
return render_to_response('registration/loggedout.html')
And finally, in urls.py:
url(r'^myapp/loggedout/$', 'myapp.views.loggedout', name='loggedout'),

django - middleware issue

I want to put a login form everywhere on my website, after following a few SO answers I decide to write my own middleware like this:
class LoginFormMiddleware(object):
'''
Put a login form in everypage of the website
'''
def process_request(self, request):
# if the top login form has been posted
if request.method == 'POST':
if 'logout_submit' in request.POST:
# log the user out
from django.contrib.auth import logout
logout(request)
form = LoginForm()
elif 'login_submit' in request.POST:
# validate the form
form = LoginForm(data=request.POST)
if form.is_valid():
# log the user in
from django.contrib.auth import login
login(request, form.get_user())
else:
form = LoginForm(request)
else:
form = LoginForm(request)
# attach the form to the request so it can be accessed
# within the templates
request.login_form = form
in my settings.py, I have:
import django.conf.global_settings as DEFAULT_SETTINGS
...
MIDDLEWARE_CLASSES = DEFAULT_SETTINGS.MIDDLEWARE_CLASSES + (
'base.mymiddleware.LoginFormMiddleware',
)
TEMPLATE_CONTEXT_PROCESSORS = DEFAULT_SETTINGS.TEMPLATE_CONTEXT_PROCESSORS + (
'django.core.context_processors.request',
)
The form, in base.html to be accesed from everywhere, looks like this:
{% if user.is_authenticated %}
<div class="login_box">
<form action="/myapp/logout/" method="post">{% csrf_token %}
<div class="col2"><a>{{ user.username }}</a></div>
<div class="col3"><input type="submit" value="Logout" name="logout_submit"/></div>
</form>
</div>
{% else %}
<form action="." method="post">
{% csrf_token %}
<div class="login_box">
<div class="error_box">
{% if request.login_form.errors %}
Incorrect User/Password
{% endif %}
</div>
<div class="col00"> <h4>{{ request.login_form.username.label_tag }}</h3></div>
<div class="col11">{{ request.login_form.username }}</div>
<div class="col22"><h4>{{ request.login_form.password.label_tag }}</h3></div>
<div class="col33">{{ request.login_form.password }}</div>
<div class="col44"><input type="submit" value="Login" name="login_submit"/></div>
<input type="hidden" name="next" value="{{ request.get_full_path }}" />
</div>
</form>
{% endif %}
Login works normally but, after doing it, each time I make a GET request user.is_authenticated seems to return false cause what I see is an empty LoginForm instead of the logout form.
I dont know if the problem is in my middleware (when request.method != 'POST' it returns form = LoginForm(request)) or it is something I am missing in my settings, or maybe using middleware for this was not a great idea...
I can't believe you have seen any SO answers that advocate putting this sort of logic in the middleware. (If you have, post the link so that I can downvote them.)
This really, really, really isn't the place to do this sort of thing. Write a specific view and set the action parameter of the login form to that view.
However, I suspect your underlying issue is that you're not using RequestContext to render the other views, so the user object is not passed to the template.
Your implementation doesn't make much sense. A login form with action attribute is "." is wrong and will lead to conflicts.
You should have a login view, not a login middleware. The action attribute of the login form should be the reversed url of your login view.
In your login form, you should specify a next hidden input for example:
<input name="next" type="hidden" value="{{ request.POST.next|default:request.path }}" />
Following that, it can be in your base template or anywhere in the website.
This is also valid for logout.