I have created loginview using class-based view concept as following:
class LoginView(NextUrlMixin,RequestformattachMixin,FormView):
form_class = login_page
template_name = 'login.html'
success_url = '/'
def form_valid(self, form):
next_url=self.get_next_url()
return redirect(next_url)
def form_invalid(self, form):
return super().form_invalid(form)
forms.py:
class login_page(forms.Form):
Email = forms.EmailField(required=True,widget=forms.EmailInput(
attrs={"class": "form-control", "placeholder": "Email
address", "id": "exampleInputEmail2"}))
Password = forms.CharField(required=True,widget=forms.PasswordInput(attrs={"class": "form-control",'id':'exampleInputPassword2',
"placeholder": "Password"}))
I have modified on my login.html page to use bootstrap modal as the following:
{% block content %}
<div id="loginModal" class="modal fade">
<div class="loginModal-content">
<div class="loginModal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Login</h4> </div><div class="loginModal-body">
<div class="row">
<div class="col-md-12"> via <div class="social-buttons">
<i class="fa fa-facebook"></i> Facebook
<i class="fa fa-twitter"></i> Twitter
</div>or
<form class="form" role="form" method="post" action="login" accept-charset="UTF-8" id="login-nav">
<div class="form-group">
<label class="sr-only" for="exampleInputEmail2">Email address</label>
{# <input type="email" class="form-control" id="exampleInputEmail2" placeholder="Email address" required>#}
{# {{ form.Email }}#}
</div>
<div class="form-group">
<label class="sr-only" for="exampleInputPassword2">Password</label>
{# <input type="password" class="form-control" id="exampleInputPassword2" placeholder="Password" required>#}
{# {{ form.Password }}#}
<div class="help-block text-right">
Forgot the password ?
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block">Sign in</button>
</div>
<div class="checkbox">
<label>
<input type="checkbox"> keep me logged-in
</label>
{{ form }}
</div>
</form>
</div>
<div class="bottom text-center"> New here ?
<b>Join Us</b> </div></div></div>
<div class="loginModal-footer">
</div>
</div>
</div>
{% endblock %}
As I am a newbie in Django, could you please help me how to use the bootstrap modal with my Django CBV
or even how to start as when I started using the Modal it is failed to appear, should I use ajax or what are other technologies should I use. please help from where could i start
Ok, the best way to render fields in django is django-widget-tweaks, this very simple and render all the error and fields with adding classes to that field.
Follow the installation of it - https://github.com/jazzband/django-widget-tweaks
here is simple and full guide of using django-widget-tweaks
I always suggest to use it, hope it will help you.
The plugin I wrote could be your starting point django-bootstrap-modal-forms. If you check the examples project you will also find a fully functional Login and Signup form in modals. You will be able to bind any form to the modal and all of the validation stuff will work out of the box.
You will create a trigger element opening the modal
Your selected form will be appended to the opened modal
On submit the form will be POSTed via AJAX request to form's URL
Unsuccessful POST request will return errors, which will be shown under form fields in modal
Successful POST request will redirects to selected success URL
Related
I’m really new in Django.
I’m trying to implement Modal dialog using forms. The problem is that even when I make some changes in my form, this changes are not shown in database… I have no idea why. When I test form outside Modal dialog, form is working…
Here is my form.py:
class anomalie_location_form(ModelForm):
class Meta:
model = Anomalie
fields = ['localization', ]
here is my view.py
#login_required(login_url='login')
def fix_anomalie_stock(request, pk, type_anomalie):
anomalie_pk = Anomalie.objects.get(id=pk)
# form to change anomalie position
form_location = anomalie_location_form(instance=anomalie_pk)
if request.method == 'POST':
print('printinng anomalie_location_form POST ', request.POST)
form_location = anomalie_location_form(
request.POST, instance=anomalie_pk)
if form_location.is_valid():
form_location.save()
return redirect('/')
context = {'anomalie_pk': anomalie_pk,
'form_location': form_location}
return render(request, "anomalie/fix_anomalie_stock.html", context)
and my html:
<div class="modal fade" id="myModal2" role="dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h4>{{product.product_name }}</h4>
</div>
<form action="" method="POST">
{% csrf_token %}
<div class="modal-body">
{{form_location}}
</div>
<div class="modal-footer">
<input type="submit" class="btn btn-primary" value="Treter" data-dismiss="modal">
</div>
</form>
</div>
</div>
</div>
this is the model.py
class Anomalie (models.Model):
ANOMALIE = (
("Etiquette absente", "Etiquette absente"),
("Etiquette decalee", "Etiquette decalee"),
("Etiquette inconnue", "Etiquette inconnue"),
)
ANOMALIE_STATE = (
("traité", "traité"),
("mise à jour", "mise à jour"),
("signalé", "signalé"),
)
type = models.CharField(
max_length=200, choices=ANOMALIE, null=False)
date_report = models.DateTimeField(null=False, blank=False)
localization = models.TextField(max_length=30, null=False, blank=False)
state = models.CharField(
max_length=200, choices=ANOMALIE_STATE, null=False)
aisle = models.ForeignKey(Aisle, null=True, on_delete=models.SET_NULL)
product = models.ForeignKey(
Product, null=True, on_delete=models.SET_NULL)
def datepublished(self):
return self.date_report.strftime('%B %d %Y')
def __str__(self):
return self.type
and this is the url.py
urlpatterns = [
path('admin/', admin.site.urls),
path('', home_screen_view, name="home"),
path('consult/<str:pk>/', consult_anomalie, name="consult_anomalie"),
path('fix_anomalie_stock/<str:pk>/<str:type_anomalie>',
fix_anomalie_stock, name="fix_anomalie_stock"),
]
So the question is why form is working outside of Dialog Modal ?
The mistake is simple.
That is, the form in the modal have a submit button. This button has the bootstrap modal data-dismiss attribute which makes the modal to dismiss and not the form to submit.
<input type="submit" class="btn btn-primary" value="Treter" data-dismiss="modal">
Remove the bootstrap data-dismiss attribute from submit button.
<input type="submit" class="btn btn-primary" value="Treter">
Code snippet in action
Run the code snippet to see it in action. I've added the modal code from the question. Form submit() to alert the form data and 'hidden.bs.modal' to alert when modal closes. For demo purpose, form has two submit buttons. One with the data-dismiss attribute and the other without. You can see that the button (2) alerts the data while the other closes the modal
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#myModal2">
Launch modal
</button>
<div class="modal fade" id="myModal2" role="dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h4>Product Name</h4>
</div>
<form action="" method="POST">
<div class="modal-body">
<input type="text" name="product" class="form-control">
(1) submit button with data-dismiss attribute<br>
(2) submit button without data-dismiss attribute
</div>
<div class="modal-footer">
<input type="submit" class="btn btn-primary" value="(1) Treter" data-dismiss="modal"> | <input type="submit" class="btn btn-primary" value="(2) Treter">
</div>
</form>
</div>
</div>
</div>
<script>
$(document).ready(function() {
console.log('start');
$('form').submit(function() {
alert($(this).serialize());
})
$('#myModal2').on('hidden.bs.modal', function (e) {
alert('modal closes');
})
});
</script>
I'm missing some details but forms often don't submit properly when inputs are not named. Even your select elements need name and value pair parameters. Have you double checked this?
What can happen with bootstrap is that the modal can confuse the form action. You have it now set to = "". Try removing the action parameter and give your form a unique id.
if request.method == 'POST':
Also try checking if submit button was posted rather than just the request method.
Modal should be inside the form tag and not the other way around.
<form action="" method="POST">{% csrf_token %}
<div class="modal fade" id="myModal2" role="dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h4>{{product.product_name }}</h4>
</div>
<div class="modal-body">
{{form_location}}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
</form>
I'm kinda new into Django and I'm facing some troubles using some custom forms.
I'm using a purchased Bootstrap theme which apart from the standard classes that comes with Bootstrap has its own classes and of course, some custom CSS. I find it very difficult how Django deals with custom forms and all the sources/information/examples found online makes no sense to me.
So, my elements from my HTML template use the following classes:
<form action="#" method="post" class="card shadow-soft border p-4 mb-4">
<div class="form-group">
<label for="video">Video url</label>
<input type="text" value="https://video.com/" class="form-control shadow-soft" id="video"
placeholder="Video url" required>
</div>
<div class="row">
<div class="col">
<button class="btn btn-primary btn-dark mt-2 animate-up-2 text-right"
type="submit">Update</button>
</div>
</div>
</form>
In forms.py I have added the following:
class UpdateURLForm(forms.Form):
VideoURL = forms.CharField(
widget=forms.TextInput(
attrs={
'class': 'form-group'
}
)
)
class Meta:
model = Listing
fields = ('VideoURL')
In views.py I have imported the form and added to the view:
from .forms import UpdateURLForm
def updateInfo(request):
if request.method == 'POST':
form = UpdateURLForm(request.POST)
if form.is_valid():
pass
else:
form = UpdateURLForm()
return render(request, 'myapp/editinfo.html', {'form': form})
Now, in my HTML template, I want to render the form field which has to inherit the custom CSS styles but somehow, I'm missing something because the field is being displayed as I was using Crispy forms.
<form action="#" method='post' class="card shadow-soft border p-4 mb-4">{% csrf_token %}
<div class="form-group">
<label for="video">Video URL</label>
<input type="text" value="{{form}}" class="form-control shadow-soft" id="video"
placeholder="{{object.VideoURL}}" required> # the placeholder comes from my class based view
</div>
<div class="row">
<div class="col">
<button class="btn btn-primary btn-dark mt-2 animate-up-2 text-right"
type="submit">Update</button>
</div>
</div>
</form>
What should I do if I need more fields from a custom form to be rendered using my custom CSS classes?
Any suggestion would be much appreciated. Thanks!
You can use Widget Tweaks to achieve what you want. This will allow you to use your own styles:
You can get Django Widget Tweaks by using pip:
$ pip install django-widget-tweaks
To enable widget_tweaks in your project you need to add it to INSTALLED_APPS in your projects settings.py file:
INSTALLED_APPS = [
...
'widget_tweaks',
...
]
Considering your code sample, when you render the form field in the HTML template, do something like:
first you need to load in the top of the HTML file (similar how you load static):
{% load widget_tweaks %}
Then you can add your custom class like this:
<div class="form-group">
<label for="video">Video URL</label>
{{form.VideoURL|add_class:"form-control shadow-soft"}}
</div>
There is already a subscribe field in my html page.
I don't want to create another django form.
how can I send data from here?
<div class="input-group">
<span class="input-group-addon fh5co_footer_text_box" id="basic-addon1"><i class="fa fa-envelope"></i></span>
<input type="text" class="form-control fh5co_footer_text_box" placeholder="Enter your email..." aria-describedby="basic-addon1">
<i class="fa fa-paper-plane-o"></i> Subscribe
</div>
You can put your code inside form tags that points to your django view:
<form action="url_of_your_view" method="post">
{% csrf_token %}
</form>
and you can get the data in your view using request.POST but don't forget the {% csrf_token %} in your form.
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 currently building a site with a contact function. I build the site with Django and Bootstrap. For contacting the people behind the site the user clicks on a element in the top navigation bar called Contact. This elements open a Bootstrap modal. At the moment the modal works as expected and looks like that:
The code is:
<div class="modal fade" id="kontakt" role="dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<form action="" class="form-horizontal">
<div class="modal-header">
<h4>Contact us</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label for="kontakt-name" class="col-lg-2 control-label">Name</label>
<div class="col-lg-10">
<input type="text" class="form-control" id="kontakt-name" placeholder="Name">
</div>
</div>
<div class="form-group">
<label for="kontakt-email" class="col-lg-2 control-label">E-Mail</label>
<div class="col-lg-10">
<input type="email" class="form-control" id="kontakt-email" placeholder="Email-Address">
</div>
</div>
<div class="form-group">
<label for="kontakt-nachricht" class="col-lg-2 control-label">Message</label>
<div class="col-lg-10">
<textarea class="form-control" id="kontakt-nachricht" rows="8"></textarea>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary" type="submit">Send</button>
Close
</div>
</form>
</div>
</div>
</div>
Because I would like to sent the data that is written by the user to the Django backend I wrote a form that is:
class ContactForm(forms.Form):
name = forms.CharField(max_length=255)
email = forms.EmailField()
message = forms.CharField(widget=forms.Textarea)
In order to offer this form to all templates (implemented in the base.html) I wrote a context preprocessor that works fine.
Is there a possibility to render the Django form to my desired html? I tried django-bootstrap3 but this app does not render the label and the input in one row. When I replace the input fields with Django (without any third party application) the class form-control and the id is wrong.