how to cancel form w/o validation in django + bootstrap4 - django

Hi i am using django + bootstrap4 to render forms. I have 'submit' and 'cancel' buttons on the forms. i am using ModelForm with Validators assigned to most of the form attributes.
template file
<form action="{% url 'actor-create' %}" method="post" class="w-25 mx-auto">
{% csrf_token %}
{% bootstrap_form form layout="horizontal" %}
<button class="btn btn-primary" type="submit"><i class="fas fa-plus"></i> Save</button>
<button class="btn btn-primary" type="submit"><i class="fas fa-times"></i> Cancel</button>
</form>
in the view
def actor_create(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
print(request.POST)
if "cancel" in request.POST:
return HttpResponseRedirect('/')
..... rest of the code
When cancel button is pressed validation of the form attributes prevents the form from submitting. so view functionality never gets executed.
I want to know how to avoid validation when form is cancelled?
Following Q&A has a JavaScript based solution, I preferably don't want to write such code for every form in my website.
How to cancel form submission?

as suggested by Iain Shelvington making it a 'a' worked for me!
<i class="fas fa-times"></i> Cancel

Related

How to assign function to button in Django

urlpatterns=[
path('login/',views.LoginUser,name='login'),
path('logout/',views.LogoutUser,name='logout'),
path('register/',views.RegisterUser,name='register'),
path('delete/<str:pk>',views.DeleteUser,name='delete'),
path('',views.home,name='home'),
#path('usersSettings/',views.UserSettings,name='userSettings'),
path('users/<str:pk>/',views.users,name='users'),
path('parameters/',views.parameters,name='parameters'),
path('EbotManual/',views.EbotManual,name='EbotManual'),
path('LedManual/',views.LedManual,name='LedManual'),
path('TestRutins/',views.TestRutins,name='TestRutins')
]
I am designing a website based on django. I want to update the user information and delete the user if wanted in the same page. I created updating and it works properly. But when I address the delete user function to same html file , the button that I want it to delete user also updates just like the other button. I need both buttons to work for their own purposes. I thought that without changing anything assigning delete function to button might help thats why I wrote the title like that. Thank you!
<div class="login--wrapper">
<form method="POST" class="form">
{% csrf_token %}
<div class="center">
<h1>Kullanıcı Ayarları</h1>
{% csrf_token %}
{% for field in form %}
<div class="mb-3">
<label for="exampleInputPassword1" class="from-label">{{field.label}}</label>
{{field}}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">Update Info</button>
<button type="submit" class="btn btn-primary">Delete User </button>
</div>
def DeleteUser(request,pk):
user=DataEbotUser.objects.get(id=pk)
if request.method=='POST':
user.delete()
context={'user':user}
return render(request,'home/UsersPage.html',context)
def users(request,pk):
user=DataEbotUser.objects.get(id=pk)
form=EditUserForm(instance=user)
if request.method=='POST':
form=EditUserForm(request.POST, instance=user)
if form.is_valid():
form.save()
context={'form':form , 'users':users}
return render(request,'home/UsersPage.html',context)
url patterns:
urlpatterns=[
path('login/',views.LoginUser,name='login'),
path('logout/',views.LogoutUser,name='logout'),
path('register/',views.RegisterUser,name='register'),
path('delete/<str:pk>',views.DeleteUser,name='delete'),
path('',views.home,name='home'),
#path('usersSettings/',views.UserSettings,name='userSettings'),
path('users/<str:pk>/',views.users,name='users'),
path('parameters/',views.parameters,name='parameters'),
path('EbotManual/',views.EbotManual,name='EbotManual'),
path('LedManual/',views.LedManual,name='LedManual'),
path('TestRutins/',views.TestRutins,name='TestRutins')
]
The problem is that your two buttons submit the form to the same page that rendered the form. There is no way to tell them apart.
If you want each button to perform a different action, one way to do this would be:
<button type="submit" class="btn btn-primary">Update Info</button>
<a class="btn btn-danger" type="button" href="{% url 'delete' user.pk %}">Delete User</a>
Since the function users is the only one to manage the update of the user's information based on the form data, the button Update Info remains in the form of submit button.
The Delete User button on the other hand is different. It simply calls the function DeleteUser passing it a pk which will be used to delete a user.
Here are some things to consider:
The function DeleteUser must not be called directly. It is the function users which must render the page.
You have to render the user object in the context of your function users, to be able to retrieve the pk of the user who will be used for the button delete
Function DeleteUser must not render the template but redirect to another url like home. Something like return redirect('home')

How Do You Trigger HTMX Page Refresh After User Updates Any Part of The Page?

I have been working with HTMX and it's pretty cool compared to the dreaded formsets and Javascript. I have it working....My only issue is when the user updates the form anywhere...you have to manually refresh the page to reset the list of todos. My issue is identical to this one...https://stackoverflow.com/questions/66664407/dynamically-update-table-when-creating-new-enty-using-htmx but there is no resolution listed.....
Here's a quick overview of my code...
My view...
def create_to_do(request):
user = User.objects.get(id=request.user.id)
to_dos = NewToDo.objects.filter(created_by=user)
form = ToDoForm(request.POST or None)
if request.method == "POST":
if form.is_valid():
to_do = form.save(commit=False)
to_do.created_by = user
to_do.creation_date = timezone.now()
to_do.save()
return redirect("MyToDoList:detail-to-do", pk=to_do.id)
else:
return render(request, "partials/to_do_form.html", {
"form":form
})
context = {
"form": form,
"user": user,
"to_dos": to_dos,
}
return render(request, "create_to_do.html", context)
Partial detailview....
<button class="button35" hx-get="{% url 'MyToDoList:update-to-do' to_do.id %}" hx-swap="outerHTML">
Update
</button>
<button class="button34" hx-post="{% url 'MyToDoList:delete-to-do' to_do.id %}" hx-swap="outerHTML">
Delete
</button>
</div>
Partial todo form....
<div hx-target="this" hx-swap="outerHTML" class="">
<form method="POST">
{% csrf_token %}
{% if to_do %}
<button class="button35" hx-post="{% url 'MyToDoList:update-to-do' to_do.id %}">
Save
</button>
<button class="button34" hx-get="{% url 'MyToDoList:detail-to-do' to_do.id %}">
Cancel
</button>
</div>
{% else %}
<button class="button35" hx-post=".">
Save
</button>
</div>
{% endif %}
</form>
</div>
My main create form html..
<button class="button36" hx-get="{% url 'MyToDoList:create-to-do-form' %}" hx-swap="beforeend" hx-target="#bookforms">Add Form</button>
<div id="bookforms" class=""></div>
<div class="">
{% if to_dos %}
{% for to_do in to_dos %}
{% include "partials/to_do_detail.html" %}
{% endfor %}
{% endif %}
After a day of playing and pulling my hair out..it's all working as I want...I just need to figure out how to incorporate a dynamic page load if anything changes so that the entire page gets reloaded....so that the records get sorted according to my number field...
Thanks in advance for any thoughts or suggestions.
So thanks to a kind soul on Facebook....I added this Javascript to my code and it works.
$(document).on("click", ".yourclass", function(){
location.reload();
});
In case you need this, I had the problem when I have to update two/mutliple parts of the page after post.
I manage to solve it by trigger_client_event
Thanks to this issue: How do I manually trigger a hx-get event of an element from JavaScript
HTMX rocks!

How to show a message dynamically in a django app?

I've created a webapp using django where in one of the section I asks for user's feedback and on clicking the submit button I send user an email thanking him for feedback.
But every time I click on submit, the page refreshes itself, the email get delivered successfully But What I want is when user click on submit I want to show a "Thank you" message right there in place of feedback form. and feedback form to get removed
Here's a section of my index.html
<form action="" method="POST">
{% csrf_token %}
<div>{{ form.message }}</div>
<div>{{ form.email }}</div>
<p class="formerrors" >{{ form.email.errors.as_text }}</p>
<hr>
<input id="submitbutton" type="submit" name="submit" value="Submit">
</form>
here's my view
def index(request):
if request.method == 'POST':
form = FeedbackForm(request.POST)
if form.is_valid():
subject = "You got a message"
message = form.cleaned_data['message']
email = form.cleaned_data['email']
actual_message = "You got a message from {} \n\n {} \n\nGo to work\nWith regards".format(email,message)
recipients = ['example#mail.com']
sender = 'example#mail.com'
send_mail(subject, actual_message, sender ,recipients,fail_silently=False)
return HttpResponseRedirect('')
else:
form = FeedbackForm()
return render(request,'my_webapp/index.html',{'form':form})
I can do this by writing a JS onClick function but is there any better way to do this? Also the built-in django messages refreshes the page I guess and are always on the top of the page.
I certainly do not want my page to get refreshed and want message appear in place of form.
You should send your form using AJAX. For the response part you could send a message from your server on successful validation and in your complete function of AJAX change the form's display property to none to remove it. Then create an element for your response message using javascript.
You could send your form with Ajax to your django view and replace your form with a thank you note on the success callback.
Actually you don't have to use AJAX to achieve this. You could use django messages framework to create messages when user submitted their form.
Like so:
from django.contrib import messages
...
if request.method == 'POST':
form = FeedbackForm(request.POST)
if form.is_valid():
...
messages.success("Thank you")
# After submitted, redirect user to current page, the form will be reset
return HttpResponseRedirect(request.path_info)
else:
form = FeedbackForm()
return render(request,'my_webapp/index.html',{'form':form})
then on your template:
{% if messages %}
{% for message in messages %}
<p class="text-danger">{{ message }}</p>
{% endfor %}
{% endif %}
<form action="" method="POST">
{% csrf_token %}
<div>{{ form.message }}</div>
<div>{{ form.email }}</div>
<p class="formerrors" >{{ form.email.errors.as_text }}</p>
<hr>
<input id="submitbutton" type="submit" name="submit" value="Submit">
</form>
Of if you want a toastr message?, reference this answer

access form data in view

I hava a form in my template which is for search.I did not made any form class to it. Is it possible to have access form data in view or should I make a form class to it.
<form class="navbar-form" role="search" action="{% url 'my_url_name' %}" method="get">
<div class="input-group add-on">
<input class="form-control" placeholder="search" name="srch-term" id="srch-term" type="text">
<div class="input-group-btn">
<button class="btn btn-default" type="submit"><i class="glyphicon glyphicon-search"></i></button>
</div>
</div>
</form>
I use this form for its style and I can not make this style with Form class
You can access form data in the request.GET (or request.POST if it is a post request) dictionary in your view. For example:
srch_term = request.GET.get('srch-term')
You can by using the QueryDict object you get with the request :
def myview(request):
if request.method == "POST":
data = request.POST
print(data['foo']) # <--Will print the value I entered into my form.
[...]
But be careful with this : There is no validation tool to ensure the data you receive is correctly formated.

Trouble getting Django ModelForm inside modal to work

OK - I'm positive that the issue is that I have some fundamental understanding of how forms work in Django, so 30,000 ft conceptual explanations are welcome, in addition to code fixes!
I'm trying to run my site from (mostly) a single view (and single template), with modal popups to view info (working) and to edit or add it (not working). I can see the form, fill it out, and click submit, at which point the modal closes, but no new Courses show up in the admin view.
I'll confine this to a single model - my simplest - for the time being:
models.py:
class Course(models.Model):
Name = models.CharField(max_length=30,unique=True)
Active = models.BooleanField(default=True)
def __unicode__(self):
return u'%s' % (self.Name)
views.py
def IndexView(request,Course_id,Section_id):
template_name = 'gbook/index.html'
print Course_id,Section_id
this_course = Course.objects.get(pk=Course_id)
active_courses = Course.objects.all().filter(Active=True).exclude(pk=Course_id)
section_list = Section.objects.all().filter(course=this_course)
if len(section_list) >1:
multi_section = True
else:
multi_section = False
active_section = Section.objects.get(pk=Section_id)
roster = Student.objects.all().filter(sections__in=[active_section])
announcement_list = Announcement.objects.all().filter(sections__in=[active_section])
courseaddform = CourseAddForm()
context = {'active_courses':active_courses, 'this_course': this_course,
'active_section':active_section, 'section_list':section_list,
'roster':roster, 'multi_section':multi_section,
'announcement_list':announcement_list, 'courseaddform':courseaddform}
return render(request,'gbook/index.html', context)
forms.py
class CourseAddForm(forms.ModelForm):
class Meta:
model = Course
fields = ['Name', 'Active']
templates/index.html
...
<li class="dropdown">
<span class="glyphicon glyphicon-cog" aria-hidden="true"></span><span class="caret"></span>
<ul class="dropdown-menu">
<li><a data-toggle="modal" data-target="#SectionRosterModal">Roster</a></li>
<li><a data-toggle="modal" data-target="#AnnouncementModal">Announcements</a></li>
<li><a data-toggle="modal" data-target="#CourseAddModal">CourseAdd</a></li>
</ul>
</li>
...
<!-- COURSE ADD MODAL -->
<div class="modal fade" id="CourseAddModal" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header" style="padding:5px 10px;">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4>Add Course</h4>
</div>
<div class="modal-body" style="padding:10px 10px;">
<form data-parsley-validate method="post" id="courseaddform" action="" enctype="multipart/form-data"
data-parsley-trigger="focusout">
{% csrf_token %}
{{ courseaddform.as_p }}
<p id="login-error"></p>
<input type="submit" class="btn btn-info submit" name="AddCourse" value="Add Course" />
</form>
</div>
<div class="modal-footer">
</div>
</div>
</div>
</div>
...
I think that there's supposed to be a POST command in there somewhere, but I really don't have a good handle on the process here. Thanks for the help!
It looks like you are not doing anything with the form data when you post back, you need to process the form if the request method is a POST
def IndexView(request, ...):
if request.method == "GET":
... do what you are doing now and return
elif request.method == "POST":
cf = CourseAddForm(request.POST)
if cf.is_valid():
...do stuff with cf.cleaned_data <---- this is a dict
return ....
You are doing the same thing for GET and POST requests right now and neither deals with the submitted form
see here for more details
https://docs.djangoproject.com/en/1.10/topics/forms/#the-view
EDIT #1:
The POST should be a standard HTTP POST request back to the same URL. Just set the method tag as you are now and action="." (or a URL lookup in the template).
You need to return a valid HTTPResponse object but the normal case when dealing with a form is to return a HTTPResponseRedirect(...some url...) if the form is valid. In the case of a single page app, if you reload the same page you need to do everything you did in the request.method == "GET" so maybe return a HTTPResponseRedirect back to the same URL. In this case, I would look at the django messages framework and add a message to the context saying the form was submitted successfully and display the message in the reloaded page (you should always check if there is a message to display anyway when using the messages framework so this will not break the case where you are loading the page for the first time)
https://docs.djangoproject.com/en/1.9/ref/contrib/messages/