I have the following abbreviated HTML for an intermediate Django admin page:
<!DOCTYPE html>
{% extends base_url %}
{% block content %}
<form action="" method="post">
...
<select name="my_name" id="my_id" required>
<option disabled selected> --- </option> <br />
...
</select>
...
<input type="hidden" name="action" value="my_action" />
<input type="submit" name="apply" value="Update" />
</form>
{% endblock %}
However, my required attribute does not seem to work, and clicking "Update" submits the form even if no selection has been made.
Am I missing something special about how Django builds intermediate pages?
Happy to provide more code if needed, just removed most of it and replaced with ... for brevity's sake.
Edit: I was able to sidestep the issue by raising an error message if my field wasn't filled out, but that seems messier since it kicks the user back to the Admin page each time:
is_valid_form = 'my_id' in request.POST
if not is_valid_form:
fail_message = (
"Error: All fields are required.")
admin_page.message_user(
request, fail_message, messages.ERROR)
return HttpResponseRedirect(request.get_full_path())
Related
I have an emergent task to make a web page which allow user to input some data and the backend do some calculation and the result needs to be displayed in the same page just below the input field (like air ticket online price check).
I am new to django and html. below is my first test web page of a simple online calculator to try to figure out how to make such web service.
I found a problem that when clicking the "submit" button, it tends to jump to a new web page or a new web tab. this is not what I want. Once the user input the data and click "submit" button, I want the "result" field on the page directly show the result (i.e. partially update only this field) without refresh/jump to the new page. Also I want the user input data kept in the same page after clicking "submit".
I saw there might be several different ways to do this work, iframe/AJAX. However, I have been searching/trying for answers and solutions for several days and none of the answers really work for this very basic simple question!!
html:
<form method="POST">
{% csrf_token %}
<div>
<label>num_1:</label>
<input type="text" name="num_1" value="1" placeholder="Enter value" />
</div>
<div>
<label>num_2:</label>
<input type="text" name="num_2" value="2" placeholder="Enter value" />
</div>
<br />
<div>{{ result }}</div>
<button type="submit">Submit</button>
</form>
view.py
def post_list(request):
result = 0
if request.method == "POST":
num1 = request.POST.get('num_1')
num2 = request.POST.get('num_2')
result = int(num1) + int(num2)
print(request.POST)
print(result)
context = {
'result': result
}
return render(request, 'blog/post_list.html', context)
I would suggest taking a look at htmx.org which makes this really simple without having to write any actual JS.
For your example:
(1) You add the htmx JS (which is only about 10k) to your HTML, and use hx-post and hx-target to trigger the ajax calls on your form. With these the form will fire an AJAX request, and the hx-target tells htmx to take the response (which you want to be only the result of your calculation) and put it in the div without refreshing the whole page.
See docs for more details on this.
Note also I gave an id to the div containing the result.
You will need to replace hx-post="{% url 'blog:post_list' %}" with the correct name to your view (which we don't know as you didn't post your urls.py).
<html>
<body>
<form method="POST" hx-post="{% url 'blog:post_list' %}" hx-target="#result">
{% csrf_token %}
<div>
<label>num_1:</label>
<input type="text" name="num_1" value="1" placeholder="Enter value" />
</div>
<div>
<label>num_2:</label>
<input type="text" name="num_2" value="2" placeholder="Enter value" />
</div>
<br />
<div id="result">{{ result }}</div>
<button type="submit">Submit</button>
</form>
<script src="https://unpkg.com/htmx.org#1.6.1"></script>
</body>
</html>
(2) In your view then you determine if the request is an AJAX request from htmx by checking the headers, in which case you want to only return the result. There are easier or elegant ways to do this (eg. check django-htmx, but just to keep it simple:
from django.http.response import HttpResponse
from django.shortcuts import render
# Create your views here.
def post_list(request):
result = 0
if request.method == "POST":
num1 = request.POST.get('num_1')
num2 = request.POST.get('num_2')
result = int(num1) + int(num2)
if request.headers.get('Hx-Request') == 'true':
# return only the result to be replaced
return HttpResponse(str(result))
else:
return render(request, 'blog/post_list.html', {'result': result})
The project have url as follows,
path('post/<str:state>/',SearchView.as_view(),name='search-data')
I have a HTML form, upon filling and submitting it supposed to pass filled form data to URL.
<form action={% url 'search-data'%} method="get" >
{% csrf_token %}
<input type="text" name="fname">
But it does not work as supposed to be.
When form submitted it gives below URL
http://127.0.0.1:8000/%7Burl?csrfmiddlewaretoken=2RZfZ4cxLB...
You don't have to pass <str:state> argument in your urlpatterns just pass path('post/search',SearchView.as_view(),name='search-data') or whatever you want but problem is when you pass an argument like this post/<str:state>/ than you have to specify that in your form action also
like this {% url 'search-data' state %} initialy you don't have any state so that's why you have to get the state name from your form so finnaly your code look like this
<form action={% url 'search-data'%} method="get" >
{% csrf_token %}
<input type="text" name="fname">
<input type="submit" value="search">
</form>
and than in your views you've to get it from request.GET method like this
def search(request):
state = request.GET.get('fname', None)
.... do whatever you want
return response_or_data
I have a django html template which has this form in it
<form action="/image_info/" method="POST" id='image_form'>
{% csrf_token %}
<button class="imginfo" name='info_button' value={{x.desc}} type="submit">info</button>
</form>
The above form will POST the value to views.py whenever the submit button is pressed. but the problem is {{x.desc}} is a sentence and has blank spaces in it so only the first word is getting posted. I need the whole sentence. How should I do it. here x is a model and desc is its object.
Thanks you.
You just need to add quotes to your value attribute
<button class="imginfo" name='info_button' value="{{x.desc}}" type="submit">info</button>
<form action="/image_info/" method="POST" id='image_form'>
{% csrf_token %}
<input type="hidden" value="{{ x.desc }}">
<button class="imginfo" name='info_button' type="submit">info</button>
</form>
use hidden input
using this for django model form, we cant create beautiful front end.
<form method="POST" action="">
{% csrf_token %}
<div class="esor">
Name: {{form.Name}}<br>
Class: {{form.Class}}<br>
Publisher: {{form.Publisher}}<br>
</div>
<input type="submit" value="submit">
</form>
Isn't there any ways so we can use html code like:
<form method="GET" action="#">
<input type="text" name="name" placeholder="Name of book">
</form>
instead of {{form.Name}} or {{form.as_p}}
Yes, you can get a beautiful interface that way, just pass the name you use in the form.py
Example:
forms.py
class NameForm(forms.ModelForm):
class Meta:
model = MyModel
fields = [
"whatever"
]
Html Template
<form method="POST">{% csrf_token %}
<input type="text" name="whatever" placeholder="Write whatever">
</form>
There are two approach I normally use:
Install widget tweaks, so you can customize your input easily:
{% load widget_tweaks %}
{{ form.Name|add_class:"css_class"|attr:"placeholder:Name of book" }}
Or 2, in your forms.py, set all the attributes you want for the field:
Name = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Name of book'}))
You can do this by giving the name of your input element same as the name of your form field. And you can get name of your form field by displaying {{ form }} in html and then inspecting the form field in your browser and then the name attribute of that field will be name of the form field.
I have a drop down with multiple select option in my html page. On form submission, I am trying to capture all of the selected options by user in that drop down. but it throws me an error instead "TypeError:'instancemethod' object is not subscriptable". Following is my template.html and views.py
Template.html:
Select packages:
<form name=automationForm action="/vsawebauto/automation/results/" method="post">
//some form elements
<select id="package" name="package[]" multiple="multiple" size="5">
{% for i in ida.package_set.all %}
<option value="{{ i.pkg_id }}">{{ i.display_name }}</option>
{% endfor %}
</select>
//some form elements
<input type="submit" id="submit" value="Submit Job" />
Views.py:
def results(request):
//some code
selected_packages = request.POST.getlist['package[]']
//some code
return HttpResponse("Selected Packages:"+selected_packages)
Note: I debugged the code as well. The request.POST object has multiple selected values. For eg. when 1 and 701 packages are selected by user, request.POST has 'package[]': ['1','701']. But the code fails when I do request.POST.getlist['package[]']
request.POST.getlist['package[]']
Should be
request.POST.getlist('package[]')
Replace [] with () which was the cause of the error.
Here is the documentation and usage of getlist.
Also, change
return HttpResponse("Selected Packages:"+selected_packages)
to
return HttpResponse("Selected Packages: %s" % selected_packages)