Twitter-Bootstrap modal and django form - django

I'd like to show last_item in a Twitter-Bootstrap modal after django form submission, however I don't know how to handle the modal. I tried the form button suggested in documentation, but it doesn't process the form data. What do I have to do?
<button data-toggle="modal" data-target="#myModal2">Submit</button>
views.py
def main(request):
if request.method == 'POST':
form = MyModelForm(request.POST)
if form.is_valid():
name = form.cleaned_data['name']
request.session['name'] = name
mm = MyModel.objects.create(name=name)
mm.save()
return HttpResponseRedirect('/') # Redirect after POST
else:
form = MyModelForm()
args = {}
args['last_item'] = MyModel.objects.all().order_by('pk').reverse()[0]
args['form'] = form
return render(request, 'form.html', args)
form.html
{% extends "base.html" %}
{% block content %}
<form method="POST" id="" action="">
{% csrf_token %}
{{ form.as_p }}
<button>Submit</button>
</form>
<div class="modal" id="myModal2" tabindex="-1" role="dialog"
aria-labelledby="myModal2Label" aria-hidden="true" style="display: none">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="myModal2Label">Modal header</h3>
</div>
<div class="modal-body">
<p>Last item: {{ last_item }}</p>
</div>
</div>
{% endblock %}
{% block scripts %}
{% endblock %}

It seems like bootstrap calls event.preventDefault() on click, which prevents the form from being submited.
You should bind your own event on this button and close the modal programaticaly.
It could look like:
$('form').submit(function() {
$('#myModal2').modal('hide');
})
I did not test this code but it should be a good start.

Related

Django Invalid Form

I have a modal with a form in it. The issue is that on invalid form it does return the form errors but it also closes the modal dialog box by rendering the home page again. It is also the home page so the return render is needed for the logging in.
How would I just return to the screen if the post fails.
def index(request):
context = {}
if request.method == "POST":
print(request.POST)
form = UserProfileForm(request.POST or None, request.FILES or None,instance=request.user)
if form.is_valid():
form.save()
return redirect('home')
else:
form = UserProfileForm()
context['form']= form
return render(request, "home.html", context)
modal
{% block content %}
<div class="modal fade" id="editProfile" tabindex="-1" role="dialog" aria-labelledby="editProfilelCenterTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="editProfileLongTtitle">Edit Profile</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
{% include 'form.html' %}
</div>
</div>
</div>
</div>
{% endblock %}
form.html
{% block content %}
<form method = "POST" action='.' enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
{% endblock %}
home.html
{% extends 'base.html' %}
{% block title %}Home{% endblock %}
{% block content %}
{% if user.is_authenticated %}
<div class="container">
{% include 'editProfileModal.html' %}
<div class='row'>
{% include 'sidebar.html' %}
</div>
</div>
{% else %}
<p>You are not logged in</p>
Log In
Sign up
{% endif %}
{% endblock %}
You need shows the modal while you're sending a POST request and the view don't send the redirect. You can try the next poor solution. It's ugly but can work:
def index(request):
context = {'is_post': False}
if request.method == "POST":
context['is_post'] = True
form = UserProfileForm(request.POST or None, request.FILES or None,instance=request.user)
if form.is_valid():
form.save()
return redirect('home')
else:
form = UserProfileForm()
context['form']= form
return render(request, "home.html", context)
{% block content %}
<div class="modal fade" id="editProfile" tabindex="-1" role="dialog" ... >
<!-- your content ... -->
</div>
<!-- Do this after jQuery loaded -->
{% if is_post %}
<script type="text/javascript">
$(window).on('load', function() {
$('#myModal').modal('show');
});
</script>
{% endif %}
{% endblock %}
You can simple return HttpResponse with form errors.
from django.http import HttpResponse
if form.is_valid():
...
else:
return HttpResponse(form.errors.as_json())
Try this:
def index(request):
context = {}
if request.method == "POST":
print(request.POST)
form = UserProfileForm(request.POST or None, request.FILES or None,instance=request.user)
if form.is_valid():
form.save()
return redirect('home')
context['form']= form
return render(request, "home.html", context)

Converting Django DeleteView to work with ajax

Im new to django and im stuck with an issue with ajax. I have the code below.
I have a django delte view. I want to use this with ajax. Right now the view is working but the CSRF Token doesnt render.
I want to try and use a class based view as im new to learn. Im not sure why the CSRF TOKEN is not being rendered in the AJAX version. It appears when a browser is used but not when ajax is used.
Can someone please help ?
view.py
class DeleteOrderItemView(SuccessMessageMixin, generic.DeleteView):
model = OrderItem
template_name = 'pos/order_item_confirm_delte.html'
# overwritten the delete to have a conformation code. Pending items do not need a conformation code.
def delete(self, *args, **kwargs):
print("I was called !")
self.object = self.get_object()
conformation_code = self.request.POST.get('cancellation_code')
if conformation_code == str(12345) or self.object.status == "Pending":
# Record code and logged in user
messages.success(self.request, "Order item {} deleted.".format(self.object.item.name))
# print cancelled KOT
return super(DeleteOrderItemView, self).delete(*args, **kwargs)
else:
messages.warning(self.request, "Incorrect conformation code.")
return HttpResponseRedirect(reverse('pos:delete_order_item', kwargs={'pk': self.object.pk}))
def get_success_url(self, **kwargs):
self.object = self.get_object()
order_pk = self.object.order.pk
return reverse_lazy('pos:order_details', kwargs={'pk': order_pk})
def render_to_response(self, context, **response_kwargs):
""" Allow AJAX requests to be handled more gracefully """
if self.request.is_ajax():
context = self.get_context_data(**response_kwargs)
rendered = render_to_string(self.template_name, context)
return JsonResponse({'delete_form': rendered}, safe=False, **response_kwargs)
else:
return super(generic.DeleteView, self).render_to_response(context, **response_kwargs)
Javascript
/* Load the delete form */
$("#js_order_list_items").on("click", "#js_remove_item", function(){
$("#modal-actions").modal("show");
remove_url = $('#js_remove_item').attr('js_delete_url')
$.ajax({
url: remove_url,
type: 'get',
dataType: 'json',
beforeSend: function () {
$("#modal-actions").modal("show");
},
success: function (data) {
console.log(data.delete_form)
$("#modal-actions .modal-content").html(data.delete_form)
}
})
});
HTML
{% load static %}
{% block content %}
<div class="container">
<br/>
<div class="col-12 alert alert-danger">
<h4>Delete item for {{ orderitem.order.customer.name }}</h4>
</div>
<div class="row">
<div class="col-6">
<ul class="list-group">
<li class="list-group-item"><strong>{{ orderitem.item.name }}</strong></li>
<li class="list-group-item">Quantity: {{ orderitem.quantity }}</li>
<li class="list-group-item">Price: {{ orderitem.price }}</li>
<li class="list-group-item">Ordered by: {{ orderitem.order.user.username }}</li>
<li class="list-group-item">
{% if messages %}
<div class="alert alert-danger" role="alert">
{% for message in messages %}
{{ message }}
{% endfor %}
</div>
{% endif %}
</li>
</ul>
</div>
</div>
<div class="row">
<div class="col-12">
<hr/>
<form method="POST" action="{% url 'pos:delete_order_item' pk=orderitem.pk %}" class="js_confirm_delete_form">
{% csrf_token %}
{% if orderitem.status == 'Confirmed' %}
<label>Cancellation Code: </label> <input type="password" id="cancellation_code" name="cancellation_code"><br/><hr/>
{% endif %}
<input type="submit" value="Confirm" class="btn btn-danger btn-large btn-lg">
<button class="btn btn-secondary btn-large btn-lg" type="button">Cancel</button>
</form>
</div>
</div>
</div>
{% endblock %}
I found the issue my self. The render_to_string needs the request passed to it for the csrf_token to work.
rendered = render_to_string(self.template_name, context, request=self.request)

Django contact form doesnt submit

I am trying to set up a contact form. I have implemented the Django-crispy-forms and now my form is not submitted (I don't have any errors).
I've added action="" to my form in my template without any success.
forms.py
class ContactForm(forms.Form):
name = forms.CharField(max_length=100, help_text='Enter your name or username')
email = forms.EmailField()
message = forms.CharField(widget=forms.Textarea(attrs={'rows': 3, 'cols': 40}), help_text='Example: I forgot my password!')
views.py
def contact_us(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
sender_name = form.cleaned_data['name']
sender_email = form.cleaned_data['email']
message = "From {0}:\n\n{1}".format(sender_name, form.cleaned_data['message'])
send_mail('PLM_Tool contact', message, sender_email, ['myadress#gmail.com'])
return redirect('home:index')
else:
form = ContactForm()
return render(request, 'accounts/contact.html', {'form': form})
urls.py
app_name = 'accounts'
urlpatterns = [path('contact/', views.contact_us, name='contact'),]
contact.html
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block main %}
<form method="post" action="">
{% csrf_token %}
<div class="row">
<div class="col-6">
{{ form.name|as_crispy_field }}
</div>
<div class="col-6">
{{ form.email|as_crispy_field }}
</div>
<div class="col-6">
{{ form.message|as_crispy_field }}
</div>
</div>
</form>
<button type="submit" class="btn btn-success">Send</button>
Cancel
<br><br>
{% endblock %}
Here is the problem, and do not give action to form
crispy forms create the field not the button.
<form method="post">
{% csrf_token %}
<div class="row">
<div class="col-6">
{{ form.name|as_crispy_field }}
</div>
<div class="col-6">
{{ form.email|as_crispy_field }}
</div>
<div class="col-6">
{{ form.message|as_crispy_field }}
</div>
</div>
<button type="submit" class="btn btn-success">Send</button>
</form>
just add the button inside the form

Can't get form errors when using crispy forms

I'm using django-crispy-forms, a third party library, in a Django project, I would like to customize a form to get the errors at top of the form, but I can't.
This is a snippet of the code:
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="col-sm-6">
<h1>Add New Task</h1>
<form action="" method="post">{% csrf_token %}
<div class="row">
<div class="col-sm-12">{{ form|as_crispy_errors:"bootstrap3" }}</div>
<div class="col-sm-10">{{ form.project|as_crispy_field }}</div>
<div class="col-sm-2" id="add-new">
Add new
</div>
</div>
<div class="row">
<div class="col-sm-12">{{ form.title|as_crispy_field }}</div>
</div>
<button class="btn btn-primary" type="submit">Add</button>
</form>
</div>
{% endblock content %}
The view:
def new_task(request):
form = NewTaskForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
return redirect('/pomodoro/home')
return render(request, 'pomodoro/new-task.html', {
'form': form,
})
This is my form:
from django import forms
from .models import Task
class NewTaskForm(forms.ModelForm):
class Meta:
model = Task
fields = ['project', 'title',]

Simple Django form in Twitter-Bootstrap modal

I'm trying to run django forms with Twitter-Bootstrap modals. I'd like to know what should I do to return to / after form submission. My views and templates are below.
url.py
urlpatterns = patterns('myapp.views',
url(r'^$', 'main'),
url(r'^add/', 'form_add'),
)
views.py
def main(request):
if request.method == 'POST':
form = MyModelForm(request.POST)
if form.is_valid():
name = form.cleaned_data['name']
request.session['name'] = name
mm = MyModel.objects.create(name=name)
mm.save()
return HttpResponseRedirect('/add') # Redirect after POST
else:
form = MyModelForm()
args = {}
args['last_item'] = MyModel.objects.all().order_by('pk').reverse()[0]
args['form'] = form
return render(request, 'form.html', args)
def form_add(request):
args = {}
name = request.session['name']
return render(request, 'add.html', args)
form.html
{% extends "base.html" %}
{% block content %}
<button type="button" data-toggle="modal"
data-target="#myModal1">Launch modal</button>
<div class="modal" id="myModal1" tabindex="-1" role="dialog"
aria-labelledby="myModal1Label" aria-hidden="true" style="display: none">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="myModal1Label">Modal header</h3>
</div>
<div class="modal-body">
<form method="POST" id="" action="">
{% csrf_token %}
{{ form.as_p }}
<button>Submit</button>
</form>
</div>
</div>
<p>Last item: {{ last_item }}</p>
{% endblock %}
{% block scripts %}
{% endblock %}
Comment converted to answer.
HttpResponseRedirect('/') instead of '/add'?