EDIT 14/07/2021
Reading this blog post (https://simpleisbetterthancomplex.com/tips/2016/08/04/django-tip-9-password-change-form.html) I understand how to prevent user logout (update_session_auth_hash(self.request, self.object) added to form_valid function) and I am very close to the solution using attempt #2
BUT
there still have "grey" screen after user pasword successfully changed and user have to click on screen to make it disappeared...
EDIT 14/07/2021
I quite closeto the solution following this tutorial https://www.abidibo.net/blog/2015/11/18/modal-django-forms-bootstrap-4/
Neverthless it is not working correctly.
attempt #1: get_success_url
I override get_success_url funtion of PasswordChangeView to redirectto index page and use SuccessMessageMixin to confirm password change. Password is correctly changed but somthig is going wrong with return (see capture below)
attemp #2: form_valid
I've tried another way overriding form_valid function that return JsonObject. Password is also changed but screen stay as modal was still opened. When I click on screen, "grey" diappeared but if I refresh page (F5) i am redirected to home page and I am disconnected without error... and message "Your password has been successfully changed" is displayed even if modal return error...
I have implemented authentification using Django django.contrib.auth and it work but I would like change_password to be displayed using modal form and Ajax.
And I do not manage to even display the form inside modal (with all validation stuff).
I have already use bootstrap modal to display information but not for form submission. As it did not call a change_password view that render change_password_form.html template, form is not available and I got an error Parameter "form" should contain a valid Django Form.
How should I do this?
urls.py
class PasswordChangeView(SuccessMessageMixin, auth_views.PasswordChangeView):
<!-- attempt #1 -->
success_message = "Your password have been changed successfully."
def get_success_url(self):
return reverse('export:index')
<!-- attempt #2 -->
# def form_valid(self, form):
# self.object = form.save()
# update_session_auth_hash(self.request, self.object) # prevent user’s auth session to be invalidated and user have to log in again
# return JsonResponse ({'data': 'success'},status = 200)
app_name = 'registration'
urlpatterns = [
...
path('change_password/', PasswordChangeView.as_view(), name='password_change'),
...
]
password_change_form.html (modified)
{% load bootstrap4 %}
<div id = "password_change" class="modal-dialog modal-lg" role="document">
<form action="{% url 'registration:password_change' %}" method="post" id="password_change" class="form">{% csrf_token %}
<div class="modal-content">
<div class='card' style="border-top-width: 0px;border-left-width: 0px;border-bottom-width: 0px;border-right-width: 0px;">
<div style="background-color:#326690;padding:5px 5px 5px 16px;color:white;font-weight:bold;border-radius: 2px 2px 0 0;">Change password</div>
<form method="post" class="form-signin">
<div class='card-body' style="padding-bottom:0px">
{% csrf_token %}
{% bootstrap_form form layout="horizontal" placeholder="None" size="medium" label_class="form-label col-md-3" %}
</div>
<hr style="margin:1px">
<div class='card-body' style="padding-top:5px;padding-bottom:5px;">
<div>
<button type="submit" class="btn block" style="float:right;background-color:#326690;color:white;min-width:110px;">{% trans 'Confirm' %}</button>
<!--<i class="fa fa-times" aria-hidden="true"></i> {% trans 'Cancel' %} -->
<span data-dismiss="modal" class="btn btn-light border" style="float:right;color:#326690;min-width:110px;margin-right:5px;"><i class="fa fa-times" aria-hidden="true"></i> {% trans 'Cancel' %}</span>
</div>
</div>
</form>
</div>
</form>
</div>
<script>
var form_options = { target: '#modal', success: function(response) {
console.log('response',response);
//obj = JSON.parse(response);
$("#password_change_confirm").append('<div class="alert alert-success"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button><span>Your password has been changed successfully.</span></div>');
} };
$('#password_change').ajaxForm(form_options);
</script>
base.html (modified)
<a data-toggle="modal" data-target="#modal" class="dropdown-item" href="{% url 'registration:password_change' %}"><i class="fa fa-key" aria-hidden="true"></i>
{% trans 'Change password' %}</a>
<div class="modal" id="modal"></div>
index.html (added)
{% extends 'layouts/base.html' %}
...
<!-- message for change password in authentification module -->
<div id="password_change_confirm" style="padding-top:10px;padding-left:10px;padding-right:10px;"></div>
{% for message in messages %}
<div class="container-fluid" style="padding:10px 10px 10px 10px;">
<div id = 'msg' class="alert {{ message.tags }} alert-dismissible" role="alert" >
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
{{ message }}
</div>
</div>
{% endfor %}
<!-- end message for change password in authentification module -->
OK, I finally find a 'hack' solution that works, do know if it is the better way but it's works:
base.html
<!-- https://www.abidibo.net/blog/2015/11/18/modal-django-forms-bootstrap-4/ -->
<div class="modal" id="modal" style="margin-top:150px;"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.form/4.3.0/jquery.form.min.js" integrity="sha384-qlmct0AOBiA2VPZkMY3+2WqkHtIQ9lSdAsAn5RUJD/3vA5MKDgSGcdmIv4ycVxyn" crossorigin="anonymous"></script>
<script type="text/javascript">
$(document).ready(function () {
$('#modal').on('show.bs.modal', function (event) {
var modal = $(this)
$.ajax({
url: "{% url 'registration:password_change' %}",
context: document.body
}).done(function(response) {
modal.html(response);
});
})
)};
registration/views.py
class PasswordChangeView(auth_views.PasswordChangeView):
def form_valid(self, form):
self.object = form.save()
update_session_auth_hash(self.request, self.object) # prevent user’s auth session to be invalidated and user have to log in again
return JsonResponse ({'data': form.is_valid()},status = 200)
registration/urls.py
app_name = 'registration'
urlpatterns = [path('change_password/', PasswordChangeView.as_view(), name='password_change'),]
registration/template/registration/password_change_form.html
<!-- https://www.abidibo.net/blog/2015/11/18/modal-django-forms-bootstrap-4/ -->
{% load i18n widget_tweaks %}
{% load bootstrap4 %}
<div id = "password_change" class="modal-dialog modal-lg" role="document">
<form action="{% url 'registration:password_change' %}" method="post" id="password_change" class="form">{% csrf_token %}
<div class="modal-content">
<div class='card' style="border-top-width: 0px;border-left-width: 0px;border-bottom-width: 0px;border-right-width: 0px;">
<div style="background-color:#326690;padding:5px 5px 5px 16px;color:white;font-weight:bold;border-radius: 2px 2px 0 0;">Change password</div>
<form method="post" class="form-signin">
<div class='card-body' style="padding-bottom:0px">
{% csrf_token %}
{% bootstrap_form form layout="horizontal" placeholder="None" size="medium" label_class="form-label col-md-3" %}
</div>
<hr style="margin:1px">
<div class='card-body' style="padding-top:5px;padding-bottom:5px;">
<div>
<button type="submit" class="btn block" style="float:right;background-color:#326690;color:white;min-width:110px;">{% trans 'Confirm' %}</button>
<span data-dismiss="modal" class="btn btn-light border" style="float:right;color:#326690;min-width:110px;margin-right:5px;"><i class="fa fa-times" aria-hidden="true"></i> {% trans 'Cancel' %}</span>
</div>
</div>
</form>
</div>
</form>
</div>
<script>
var form_options = { target: '#modal', success: function(response) {
<!-- test for form validation status: password changed confirmation message displayed only if form is valid -->
if(response.data == true){
<!-- remove grey background -->
$('body').removeClass('modal-open');
$('.modal-backdrop').remove();
$("#password_change_confirm").append('<div class="alert alert-success"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button><span>Your password has been changed successfully.</span></div>');
}
} };
$('#password_change').ajaxForm(form_options);
</script>
myapp/emplate/myapp/index.html
<!-- message for change password in authentification module -->
<div id="password_change_confirm" style="padding-top:10px;padding-left:10px;padding-right:10px;"></div>
Related
I am using jquery.bootstrap.modal.forms.js to load Login and Register form from their url as Modals using the code below:
<script>
$(function ($, undefined) {
// log in & sign up buttons
$(".register-btn").modalForm({
modalID: "#registerModal",
formURL: "/register-modal/",
});
});
$(function ($, undefined) {
// log in & sign up buttons
$(".login-btn").modalForm({
modalID: "#registerModal",
formURL: "/login-modal/",
});
});
$(function ($, undefined) {
// log in & sign up buttons
$(".forgot-password").modalForm({
modalID: "#registerModal",
formURL: "/recover-modal/",
});
});
</script>
HTML code for the modal
<div class="modal fade" id="registerModal" tabindex="-1" role="dialog" aria-labelledby="registerModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document" style="width:400px;">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="registerModalLabel">Register</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
Modal Code :
{% extends 'base.html' %}
{% load static %}
{% block title %} Login {% endblock %}
{% block style %}
{% endblock %}
{% block content %}
<div class="container-fluid ">
<div class="row ">
<div class="col-sm-12 col-xs-12 col-md-12">
<form class="account-register form-narrow p-3 mb-4 bg-white" id="login_form" method="POST"
action="" autocomplete="off">
{% if messages %}
<div id="messages">
{% for message in messages %}
<div class="alert alert-dismissible alert-info"
role="alert">
<button type="button" class="close" data-dismiss="alert"
aria-label="Close">
<span aria-hidden="true">×</span>
</button>
{{ message|escape }}
</div>
{% endfor %}
</div>
{% endif %}
{% if form.non_field_errors %}
<div id="messages">
{% for message in form.non_field_errors %}
<div class="alert alert-dismissible alert-danger"
role="alert">
<button type="button" class="close" data-dismiss="alert"
aria-label="Close">
<span aria-hidden="true">×</span>
</button>
{{ message|escape }}
</div>
{% endfor %}
</div>
{% endif %}
<div class="text-center">
<h4><i class="fa fa-lock fa-3x"></i></h4>
</div>
<h4 class="text-center mb-5">Login </h4>
{% csrf_token %}
<div class="form-group{% if form.username.errors %} has-error{% endif %}" >
<label class="control-label" for="id_username">Email Address</label>
<input class="form-control input-lg" id="id_username" maxlength="150" name="username" pattern="[a-z0-9._%+-]+#[a-z0-9.-]+\.[a-z]{2,4}$" type="text" required />
<div class="error-block">{{ form.username.errors }}</div>
</div>
<div class="form-group{% if form.password.errors %} has-error{% endif %}">
<label class="control-label" for="id_password">Password</label>
<div class="input-group input-group-lg">
</div>
<input class="form-control input-lg" id="id_password" name="password" type="password" required />
<div class="error-block">{{ form.password.errors }}</div>
</div>
<div class="g-recaptcha mb-2" data-sitekey="6LebmPsZAAAAADT_1QjnC70TJ2aiBX1a9rqWmhev"
style="transform:scale(1.1);-webkit-transform:scale(1.1);transform-origin:0 0;-webkit-transform-origin:0 0;">
</div>
<button type="submit" name="login"
class="btn btn-danger btn-sm btn-block text-uppercase shadow-4 mb-4" >
Login<i class="fa fa-sign-in" aria-hidden="true"></i>
</button>
<br/>
<p class="text-center">
Don't have an account?<button type="button" class="register-btn a btn btn-link" style="font-size:14px; margin-top:-4px;">Register </button>
</p>
<br/>
<p class="text-center text-primary">
<button type="button" class="forgot-password a btn btn-link" style="font-size:14px; text-decoration:none;">Forgot user ID and/or password? </button>
</p>
</form>
</div>
</div>
</div>
<!-- /container -->
{% endblock %}
{% block scripts %}
<script src="{% static 'js/toggle.js' %}"></script>
<script src="{% static 'js/floating-wpp.min.js' %}"></script>
<script src="{% static 'js/jquery.magnific-popup.js' %}"></script>
<script src="{% static 'js/qoc_home.js' %}"></script>
<script src='https://www.google.com/recaptcha/api.js'></script>
<script src="{% static 'js/jquery.bootstrap.modal.forms.js' %}"></script>
<script>
$(document).ready(function(){
$("#login_form").on("submit", function(){
$("#pageloader").css('visibility', 'visible');
});//submit
});
$(function ($, undefined) {
// log in & sign up buttons
$(".register-btn").modalForm({
modalID: "#registerModal",
formURL: "/register-modal/",
});
});
$(function ($, undefined) {
// log in & sign up buttons
$(".forgot-password").modalForm({
modalID: "#registerModal",
formURL: "/recover-modal/",
});
});
</script>
{% endblock %}
LoginView Code
class LoginViewModal(FormView):
template_name = 'login-modal.html'
form_class = LoginForm
success_url = '/dashboard'
def get(self, request, *args, **kwargs):
if request.user.is_authenticated:
return redirect ("/dashboard")
else:
return super(LoginViewModal, self).get(request, *args, **kwargs)
def dispatch(self, request, *args, **kwargs):
if (self.request.user.is_authenticated) and (self.request.user.user_type==4):
return redirect('/dashboard')
else:
return super().dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
"""Use this to add extra context."""
context = super(LoginViewModal, self).get_context_data(**kwargs)
if 'show_captcha' in self.request.session:
show_captcha = self.request.session['show_captcha']
context['show_captcha'] = True
return context
def form_valid(self, form):
user = form.login(self.request)
recaptcha_response = self.request.POST.get('g-recaptcha-response')
url = 'https://www.google.com/recaptcha/api/siteverify'
payload = {
'secret': settings.GOOGLE_RECAPTCHA_SECRET_KEY,
'response': recaptcha_response
}
data = urllib.parse.urlencode(payload).encode()
req = urllib.request.Request(url, data=data)
# verify the token submitted with the form is valid
response = urllib.request.urlopen(req)
result = json.loads(response.read().decode())
if result['success']:
if user.two_factor_auth is False and (user.phone_number_verified is True):
login(self.request, user)
try:
UserLog.objects.filter(username=user.id).update(failed_attempt=0)
except Exception:
print("No failed attempts ")
return redirect('/dashboard')
else:
try:
response = send_verfication_code(user)
pass
except Exception as e:
messages.add_message(self.request, messages.ERROR,
'verification code not sent. \n'
'Please retry logging in.')
return redirect('/login')
data = json.loads(response.text)
if data['success'] == False:
messages.add_message(self.request, messages.ERROR,
data['message'])
return redirect('/login')
if data['success'] == True:
self.request.method = "GET"
print(self.request.method)
kwargs = {'user':user}
return PhoneVerificationView(self.request, **kwargs)
else:
messages.add_message(self.request, messages.ERROR,
data['message'])
return redirect('/login')
else:
messages.add_message(self.request, messages.ERROR, 'Invalid reCAPTCHA. Please try again.')
return redirect('/login')
When an error occurs in the form (for example if the user enters incorrect password. The modal redirects to /login-modal/ and a full page with login form is seen instead of returning to the same modal. What can I do in order to stay on the modal when error occurs ?
Correct me if I am wrong, what you are trying to achieve here is that when a user enters incorrect credentials, for example, you want to show an error message on the page without having to reload so that the credentials are not lost? if that is the case, you must use AJAX/fetch API, I'd go for AJAX since you're already using jquery, you can send the data using jquery $.post
Implementing AJAX with Django is a bit complicated but a simple google search would do, this tutorial explains how to implement a login and signup mechanism using ajax and Django.
Now if you just want to show the modal again when an error you could have an error variable as a boolean, with 0 being no errors and 1 being the opposite, and pass it to your front-end, and have a script tag in your HTML that will trigger the modal when there is an error.
I am learning Django 2.2 and using a little bit of Bootstrap 4 to help with the front end. I have a Model created which stores some user information like first name and last name. I have created a DeleteView class which is supposed to delete entries from the database using the ID. Everything works fine as is. But if I try to implement the DeleteView class using a Bootstrap modal window, nothing seems to happen even if I click the submit button. I am not sure what I am doing wrong. I read in another thread here in Stackoverflow that we need to include the button inside a form which I have done too. But it still doesn't delete the entry. Below is all the code required.
Note - I have placed the Delete button inside the contacts_view.html file. The contacts_delete.html file is exactly the same. My idea is to provide the user to not just view the details but also update or even delete the specific entry. When I click on the Delete button, the modal pop up window appears. But when I click on the 'Confirm' button, the entry does not get deleted as required.
Please let me know how to proceed with this.
contacts_view.html / contacts_delete.html
{% extends 'base.html' %}
{% block content %}
<div class="container" style="width: 500px">
<div>
<div class="list-group" style="color: black">
<a class="list-group-item list-group-item-action my-1" style="background-color: wheat">
<div class="row">
<div class="col-4">
First Name
</div>
<div class="col-8">
{{ object.first_name }}
</div>
</div>
</a>
<a class="list-group-item list-group-item-action my-1" style="background-color: wheat">
<div class="row">
<div class="col-4">
last Name
</div>
<div class="col-8">
{{ object.last_name }}
</div>
</div>
</a>
</div>
</div>
<div class="border-top text-center my-4 pt-3">
<a class="btn btn-outline-danger ml-2" href="{% url 'contacts-delete' object.id %}" type="submit" data-toggle="modal" data-target="#myModal">Delete</a>
<!-- Modal -->
<div class="modal fade" id="myModal" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content" style="background-color: whitesmoke; color: dimgray">
<div class="modal-header">
<h4 class="modal-title">Delete Contact</h4>
<button type="button" class="close" data-dismiss="modal">×</button>
</div>
<div class="modal-body text-left">
form
<p>Do you really want to delete {{ object.first_name }} {{ object.last_name }}?</p>
</div>
<div class="modal-footer">
<form method="POST" action="{% url 'contacts-delete' object.id %}">
{% csrf_token %}
<button class="btn btn-outline-warning ml-2" type="submit">Update</button>
<button type="button" class="btn btn-outline-danger" href="{% url 'contacts-delete' object.id %}" data-dismiss="modal">Delete</button>
</form>
<a type="button" class="btn btn-outline-secondary" href="{% url 'contacts-view' object.id %}" data-dismiss="modal">Cancel</a>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock content %}
views.py
from .models import Contact
from django.urls import reverse_lazy
from django.shortcuts import reverse
from django.views.generic import DetailView, DeleteView
class ContactDetailView(DetailView):
model = Contact
template_name = 'contacts/contacts_view.html'
class ContactDeleteView(DeleteView):
model = Contact
template_name = 'contacts_update.html'
success_url = reverse_lazy('contacts-browse')
models.py
from django.db import models
from django.contrib.auth.models import User
class Contact(models.Model):
added_by = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
first_name = models.CharField(max_length=35)
last_name = models.CharField(max_length=35, blank=True, default='')
def __str__(self):
return f"{self.first_name} {self.last_name}"
urls.py
from django.urls import path
from .views import ContactDetailView, ContactDeleteView
urlpatterns = [
path('view/<int:pk>/', ContactDetailView.as_view(), name='contacts-view'),
path('view/<int:pk>/delete/', ContactDeleteView.as_view(), name='contacts-delete'),
]
How can I trigger the bootstrap modal to popup after my django form was submitted?
In my index.html template I have a standard looking modal like this
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
below in the same index.html I have a django form
{{ form.non_field_errors }}
{% csrf_token %}
<ul id="robul">
<div class="form-group">
<div class="col-xs-6">
<li id="name" name="{{ form.name.name }}" class="form-control">{{ form.name }}</li>
</div>
</div>
<div class="form-group">
<div class="col-xs-6">
<li id="email" class="form-control">{{ form.email }}</li>
</div>
</div>
<div class="form-group">
<div class="col-xs-6">
<li id="contactmessage" class="form-control">{{ form.contactmessage }}</li>
</div>
</div>
</ul>
in my view.py it looks like this:
if request.method == 'POST':
form = forms.FormName(request.POST)
if form.is_valid():
contact_name = request.POST.get(
'name', '')
contact_email = request.POST.get(
'email', '')
form_content = request.POST.get('contactmessage', '')
template = get_template('contact_template.txt')
context = {'name': contact_name,
'email': contact_email,
'contactmessage': form_content,}
content = template.render(context)
mail = EmailMessage("New contact form submission", content, "Some Name" +'', ['somegmail#gmail.com'],
headers = {'Reply-To': "noreply#gmail.com" })
mail.send()
return render(request, 'index.html', {'form': form})
The modal and JS code to trigger it live in a different context than your Django form submission code. Rendering 'index.html' is basically starting fresh when you're returning from your form submission, so it essentially amounts to showing the modal on page load. But, maybe you only want to show it after a successful submit. What you'll have to do is have some JS code to show the modal on page load, and have something in your template rendering context to conditionally render that. Here's what I'm thinking:
In index.html:
{% if successful_submit %}
<script type="text/javascript">
$(document).ready(function(){
$("#exampleModal").modal('show');
});
</script>
{% endif %}
In your view function, add the successful_submit context variable to your return:
return render(request, 'index.html', {'form': form, 'successful_submit': True})
Now, that <script> tag will only be rendered if successful_submit is True, which will only be set after a successful form POST.
Although my User login is working perfectly fine but I am unable to handle User form validation on modal itself. I mean, I am able to get the user name and pwd and validate it but if the user name and pwd didn't match, the page is redirected to a Django template. But I want to show the message like username pwd didn't match on modal itself not on another Django template.
Modal code
<div class="modal signUpContent fade" id="ModalLogin" tabindex="-1" role="dialog">
<div class="modal-dialog ">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"> × </button>
<h3 class="modal-title-site text-center"> Login </h3>
</div>
<div class="modal-body">
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
{% if next %}
{% if user.is_authenticated %}
<p>Your account doesn't have access to this page. To proceed,
please login with an account that has access.</p>
{% else %}
<p>Please login to see this page.</p>
{% endif %}
{% endif %}
<form action="{% url 'django.contrib.auth.views.login' %}" method="post">
{% csrf_token %}
{% if next %}
<input type="hidden" name="next" value="{{ next }}" />
{% endif %}
<div class="form-group login-username">
<div>
<input name="username" id="login-user" class="form-control input" size="20" placeholder="Enter Username" type="text" value="{{ username }}">
</div>
</div>
<div class="form-group login-password">
<div>
<input name="password" id="login-password" class="form-control input" size="20" placeholder="Password" type="password" value="">
</div>
</div>
<div class="form-group">
<div>
<div class="checkbox login-remember">
<label>
<input name="rememberme" value="forever" checked="checked" type="checkbox">
Remember Me
</label>
</div>
</div>
</div>
<div>
<div>
<input name="submit" class="btn btn-block btn-lg btn-primary" value="Log In" type="submit">
</div>
</div>
</form>
</div>
<div class="modal-footer">
<p class="text-center"> Not here before? <a data-toggle="modal" data-dismiss="modal" ng-href="#ModalSignup"> Sign Up. </a> <br>
<a data-toggle="modal" data-dismiss="modal" ng-href="#ModalPwdReset"> Lost your password? </a> </p>
</div>
</div>
</div>
setting.py
LOGIN_URL = '/login/'
LOGIN_REDIRECT_URL = '/index'
So, how to get error message on modal form itself ?
I have been having the same issue, I wanted to use the Django build in authentication system to make a login page for my portfolio/blog website, this means that I am not implementing custom forms/views at all for this, and I just create the view in the url.py directly from django.contrib.auth.views.login , I found a workaround that helps to my case, and maybe putting some logic in it others could find a way to adjust the idea to their projects as well, here is the code:
urls.py :
from django.conf.urls import url, include
from django.contrib import admin
from . import views as view
from django.contrib.auth import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^coltapp/', include('coltapp.urls')),
url(r'^$', view.HomePage.as_view(), name='home'),
url(r'accounts/login/$', views.login, name='login'),
url(r'accounts/logout/$', views.logout, name='logout', kwargs={'next_page': '/'}),
]
Notice this line:
url(r'accounts/login/$', views.login, name='login'),
Here I am using the build In Django login view - views.login - , so , like i said before, no custom form or views created for this pourpose.
Base.html
I am calling the modal as the bootstrap documentation recommend it, also, I am including this custom_modal.html inside of the base.html so i can use it in future operations; I have to point out that I have this on a nav-var, that's why is inside of a list item tag.
<li><a id="loginAnchor" data-toggle="modal" href="{% url 'login' %}" data-target="#custom_modal"><span class="glyphicon glyphicon-user"></span></a></li>
{# THIS WILL INCLUDE THE MODAL CONTACT WINDOW FOR FURTHER USE #}
{% include "coltapp/custom_modal.html" %}
custom_modal.html
a simple .html file with JUST the logic structure for the modal to work, but nothing else inside, no extended from base no nothing just as you can see.
<!-- Modal HTML -->
<div id="custom_modal" class="modal fade" >
<div class="modal-dialog">
<div class="modal-content modal-custom" >
</div>
</div>
</div>
In this way, i make this modal reusable, and after I will be able to inject any other data that I want inside of modal-content div by Ajax or whatever.
login.html
Here I managed the Rendering fields manually, I found this more practical as I have total control over each field from this form, remember, I have no view/form code for this login view, this comes with Django build-in auth views
<div id="login-jumbo" class="jumbotron">
<div style="margin-bottom:1%" class="modal-header">
<button id="login_close" type="button" class="close .login-close" data-dismiss="modal" aria-hidden="true">×</button>
<h1>Welcome back Nestor!</h1>
</div>
{% if form.errors %}
{% for error in form.non_field_errors %}
<div class="error-message">
<div class="alert alert-danger">
<h4>Ops! Invalid Data...</h4>
</div>
<ul><li><h5>{{ error|safe }}</h5></li></ul>
</div>
{% endfor %}
<script type="text/javascript">
var divisor = document.querySelectorAll(".form-div");
var len = divisor.length
for (let i=0; i < len; i++ ){
divisor[i].className += " has-error";
}
</script>
{% endif %}
<form id="login_form" action="{% url 'login' %}" method="POST">
{% csrf_token %}
{% for field in form.fields %}
{% if field == 'username' %}
<div class="form-group form-div">
<h4 class="control-label">{{ field|title }}</h4>
<input class="form-control" type="text" name="username">
</div>
{% else %}
<div class="form-group form-div">
<h4 class="control-label">{{ field|title }}</h4>
<input class="form-control" type="password" name="password">
</div>
{% endif %}
{% endfor %}
<div style="margin-top:2%" id="login_footer" align="right" class="modal-footer">
<button type="submit" class="btn btn-danger" value="login">Log In</button>
<input type="hidden" name="next" value="{{ next }}">
</div>
</form>
</div>
Have to note: I've managed the errors inside of this template,
{% if form.errors %} then I will call an alert message from bootstrap, this is really important for what I'm going to do in the next section in the JS file, also I've iterated over the fields and put them into a div in pairs, login, and password fields, and also I have made a little script that will add a class to those divs in case of errors found on form. class='has-error', these error classes comes directly from bootstrap for error handling.
- this is the data that will be rendered inside of the modal!
Jquery ajax request
The Ajax call is very self-explained, and also there are a lot of reference on internet about this o about how they have to be implemented
$(document).on('submit','#login_form', function(e){
e.preventDefault();
var login_form = $('#login_form');
var action = login_form.attr('action');
var method = login_form.attr('method');
var data_ = login_form.serialize();
$.ajax({
type: method,
url: action,
data: data_,
success: function(data, status) {
if ($(data).find('.alert-danger').length > 0) {
$('.modal-custom').html(data);
// console.log(data)
}else{
console.log('Log In Form Successfuly Summited')
$('#custom_modal').modal('hide')
location.reload(); //Reload the current document page on success
}
}
});
return false;
});
going through this, you pass the necessary data to the ajax call, and if this function is a success, you will apply some logic:
If find any element with ('.alert-danger') class on it, this means that the form has some errors on it, (you could use 'has-error' too), so if this condition is true, keep the modal open, and send the data again with the line:
$('.modal-custom').html(data);
'modal-custom' is the inner div from the custom_modal.html, where everything is rendered.
If not errors in form, that means no ('.alert-danger') class found on it, hide the modal, and reload the current document location, it means to reload the actual URL on the web browser, I made this because is a modal login page, sI i will need some elements to appear after the user is logged In.
also, I made to little more procs to clean the modal from errors on hiding, because if I was not logged In, and close the modal again without re-loading any page, these errors will appear again on the modal, so this was more for a cleanness procedure.
var restoreModalOnClose = function(){
var error_fields = $('.has-error')
var danger_pop = $('.alert-danger')
danger_pop.parent().remove()
$.each(error_fields, function(index, value){
$(value).removeClass('has-error');
// console.log(value)
})
};
$('#custom_modal').on('hidden.bs.modal', function (e){
console.log('here')
restoreModalOnClose()
});
I hope this helps to anyone in the future, I been reading a lot of post, docs and etc etc, and at the end, i found a workaround what satisfied what I was looking for.
JPG reference:
You can override the clean method:
from django.core.exceptions import ValidationError
class MyForm(forms.ModelForm):
.... # your code here
def clean(self):
if wrong_credentiels():
raise ValidationError("username pwd didn't match")
wrong_credentiels is a method where you can put in your verification logic
I am strating to learn Django and I want to display some forms in bootstrap modal view.
I have a template with a HTML table, this table have a column with a drop down button with several options.
the table is rendered with django-tables2 and the forms are rendered with django-crispy-forms
My form definition for the modal form:
class RecepcionForm(forms.ModelForm):
fecha_recepcion = forms.DateField(widget=DateInput())
def __init__(self,*args,**kwargs):
super(RecepcionForm,self).__init__(*args,**kwargs)
self.helper = FormHelper(self)
self.helper.layout = Layout(
Field('id_proveedor',
'anio',
'mes',
'usuario',
readonly = True
),
Fieldset('',
'fecha_recepcion',
'num_archivos',
Submit('save','Grabar'),
HTML('<a class="btn btn-danger" href={% url "monitor" %}>Cancelar</a>')
)
)
class Meta:
model = DetalleRecepcion
My view for the modal form:
#login_required(login_url='/login/')
def RecepModalView(request):
idp = request.GET.get('i')
anio = request.GET.get('a')
mes = request.GET.get('m')
if request.method == 'POST':
r = DetalleRecepcion.objects.get(id_proveedor=idp,anio=anio,mes=mes)
form = RecepcionForm(request.POST, instance=r)
if form.is_valid():
form.save()
return HttpResponseRedirect('/monitor/')
else:
r = DetalleRecepcion.objects.get(id_proveedor=idp,anio=anio,mes=mes)
r.usuario = request.user
form = RecepcionForm(instance=r)
return render_to_response('recepmodal.html',
{'form':form},
context_instance=RequestContext(request))
My template for the modal form
{% load crispy_forms_tags %}
<div class="modal fade" id="recmodal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Register </h4>
</div>
<div class="modal-body">
<form action="" method=post">
<div class="tab-content">
<div class="tab-pane active" id="tab1">
{% crispy form %}
</div>
</form>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary">Submit</button>
</div>
</div>
</div>
</div>
I don't know how to open and pass arguments to the modal form.
I try using the django tag include
Example snippet:
<body>
<table>
.
.
.
</table>
{% include 'recmodal.html' %}
</body>
but I get this error
Exception Value: Failed lookup for key [form] in
In simple word how can I pass values and open a bootstrap modal form in django using django-crispy-forms.
Any advice
Thansk in advance
I know it's too late to answer, but I render my forms in a modal using this into a "modal-body" tag:
<form method="post">
{% csrf_token %}
{% form.as_p %}
</form>
I hope this work for all people like me that we came here finding an answer.
Regards.