I'm trying to implement a form of a single field in Django. The objective is to pass an integer variable (counter) to the views.py file. The template is completely custom, the value of the variable "counter" is shown in the screen while it can be increased/decreased using two buttons.
I can't manage to read this variable from my views.py file, and I have no idea what I am doing wrong. This is what I've done:
Template file:
<form method="POST" action="{% url 'animo' ejercicio=ejercicio %}">{% csrf_token %}
<p class="mensaje">{{pregunta_valoracion}}</p>
<div id="contadormin">
<input type="button" id="number-change-button" value="-" onclick="subtract()" name="counter"/>
<div id="minutos">
<p id="counter">0 {{unidad}}</p>
</div><script>
var i = 0;
var uni = {{unidad}};
function add() {
document.getElementById('counter').value = ++i;
document.getElementById('counter').innerHTML = i;
}
function subtract() {
if (i> 0){
document.getElementById('counter').value = --i;
document.getElementById('counter').innerHTML = i;
}
}
</script>
<input type="button" id="number-change-button" value="+" onclick="add()" name="counter" />
</div>
<input type="submit" class="save btn btn-default" value= "HECHO"</input>
</form>
Views file:
if request.method == 'POST':
veces = request.POST.get('counter', '')
Any ideas?
The only items with name="counter" in your template are the + and - buttons. You don't actually have a field containing the counter value itself, so there's no way it can be submitted in the form.
Remove the "counter" names from those buttons, and instead of putting the counter value in a <p> element, put it in an <input name="counter">.
Related
In my page I have two different forms. I want to read the information from the first form whenever I press a button in the second form. Is this possible?
First form:
<form id="loadData" method="post" action="/loadData">
{% if day %}
Day: <input id="day" name="day" size="5px" value={{day}}>
Month: <input id="month" name="month" size="5px" value={{month}}>
Year: <input id="year" name="year" size="5px" value={{year}}>
{% else %}
Day: <input id="day" name="day" size="5px">
Month: <input id="month" name="month" size="5px">
Year: <input id="year" name="year" size="5px">
{% endif %}
.
.
.
</form>
Second form:
<form id="createFile" method="post" action="/createFile">
<button type="submit">Create</button>
</form>
By clicking the button in the second form I want to read the information in the first one to create a file containing all those information.
I tried something like
#app.route("/createFile", methods=["GET", "POST"])
def createFile():
if request.method == "POST":
day = request.form["day"]
month = request.form["month"]
year = request.form["year"]
return redirect('/')
but I can't manage to read those variable properly.
Despite corresponding in the comments i'm not entirely sure this is your end goal, but let's give it a go?
basically all i did was copy stuff from the links attached in the comment.
a.html:
<form id="form_id" action="/loadData" method="POST">
<input type="text" name="q" value="abcd">
<button type="submit">loadData</button>
</form>
<button id="createFile"> createFile </button>
<script>
function post(path, params, method = 'post') {
// The rest of this code assumes you are not using a library.
// It can be made less verbose if you use one.
const form = document.createElement('form');
form.method = method;
form.action = path;
for (const key in params) {
if (params.hasOwnProperty(key)) {
const hiddenField = document.createElement('input');
hiddenField.type = 'hidden';
hiddenField.name = key;
hiddenField.value = params[key];
form.appendChild(hiddenField);
}
}
document.body.appendChild(form);
form.submit();
}
var form_1 = document.querySelector('#form_id')
document.querySelector('#createFile').addEventListener('click', (e) => {
var data = Object.fromEntries(new FormData(form_1).entries());
post("/createFile",data)
});
</script>
app.py:
from crypt import methods
from flask import Flask, request
app = Flask(__name__)
#app.route("/loadData", methods=["POST"])
def loadData():
data = request.get_data()
return f"<h1 style='color:blue'>loadData data: {data}</h1>"
#app.route("/createFile", methods=["POST"])
def createFile():
data = request.get_data()
return f"<h1 style='color:red'>createFile data: {data}</h1>"
if __name__ == "__main__":
app.run(host='0.0.0.0')
page looks like this:
clicking on loadData:
clicking on createFile:
this whole setup is pretty convoluted and unnecessarily complex. what are you trying to achieve?
I'd like to fill / update a div area in index.html with the result from the python function, but I don't know how to do this. I know there are several other questions with a similar topic but I couldn't succeed with them because they were too specific. I'm pulling my hair out over this.
Would be someone so nice and guide me?
This is a function in main.py:
#app.route('/')
def index():
return render_template('index.html')
#app.route('/stat/')
def stat():
a = 2
b = 10
return(str(a) + ' is not ' + str(b))
this is the index.html:
<body>
<form action="/stat/">
<button type="submit" id="btn1" class="btn btn-primary btn-sm">check stat</button>
</form>
<div id="stat_content"></div>
</body>
As #S3DEV points out, you will need to pass the string to the template via an additional argument. For example, we might do something like this:
#app.route('/stat/', methods=['GET', 'POST']) # EDIT
def stat():
a = 2
b = 10
text = f"{a} is not equal to {b}"
return render_template("index.html", text=text)
In the code above, we set text to be the string to be passed to the template. In the template, we will be able to access this string variable as text.
Now when index.html is rendered, it will be looking for the text variable that is passed in from the Flask application. This is taken care of by Jinja 2, which is the rendering engine used by Flask.
<div id="stat_content">
{% if text %}
<h2>No text to show</h2>
{% else %}
<h2>{{ text }}</h2>
{% endif %}
</div>
Using Jinja 2 syntax with curly braces, we first check if the text variable exists or not; if it does not exist, we render the message, "No text to show." This will happen when we first route into "/", or the default home route of the Flask app.
Once the user fills out the form, however, they will be redirected to "/stat/", at which point we will now have generated text and passed it back to index.html via the render_template("index.html", text=text) function call. Then, when Jinja 2 renders index.html, it will see that text was passed over from the Flask app and display that message, namely that 2 is not equal to 10.
You want this initiated from the button right? Here's how to achieve that with ajax...
<body>
<form action="/stat/">
<button type="submit" onclick="GetData();" id="btn1" class="btn btn-primary btn-sm">check stat</button>
</form>
<div id="stat_content"></div>
</body>
<script type="text/javascript">
function GetData() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) { // XMLHttpRequest.DONE == 4
if (xmlhttp.status == 200) {
document.getElementById("stat_content").innerHTML = xmlhttp.responseText;
}
else if (xmlhttp.status == 400) {
alert('There was an error 400');
}
else {
alert('something else other than 200 was returned');
}
}
};
xmlhttp.open("GET", "/stat/", true);
xmlhttp.send();
}
</script>
to update the content of that div, i think (based on your logic) you need to perform an ajax call to your stat function with the two parameters a and b submitted via POST request:
<form class="form-stat needs-validation" novalidate role="form">
<div class="form-group">
<input type="text" class="form-control" name="a" value="">
<div class="invalid-feedback"></div>
</div>
<div class="form-group">
<input type="text" class="form-control" name="b" value="">
<div class="invalid-feedback"></div>
</div>
<button type="submit" id="btn1" class="btn btn-primary btn-sm">check stat</button>
</form>
<div id="stat_content">Output: ?</div>
put the javascript code below after jquery call
<script>
$(document).ready(function() {
"use strict";
$('.form-stat').submit(function(e) {
e.preventDefault();
$.ajax({
url: "{{ url_for('stat') }}",
type: 'POST',
cache: false,
dataType: 'json',
data: $('.form-stat').serialize(),
success: function(data) {
// console.log(data);
$('.form-stat input[name=a]').val(''); // reset field
$('.form-stat input[name=b]').val(''); // reset field
$('#stat_content').html(data); // update div with the returned vlue
}
});
});
});
</script>
and you have to make little change to your stat function so you can submit dynamically the two parameters via POST like so :
from flask import Flask, request, make_response
import json
#app.route('/stat', methods=['POST'])
def stat():
if request.method == 'POST':
a = request.form['a']
b = request.form['b']
# check if inputs are valid to work with ..
res = str(a) + ' is not ' + str(b) if a != b else str(a) + ' and ' + str(b) + ' are equal.'
resp = make_response(json.dumps(res))
resp.status_code = 200
return resp
Sorry before that i have bad english. So i want to send data from django form with ajax and javascript, but the problem is i have add button to add more field, every time i add field the field id increase
i already tried with single form id, its success, but with multiple dynamic id it fail
My html :
{{ ipform.management_form }}
{% for form in ipform %}
<div class="form-group">
<div class="row form-row spacer">
<div class="col-2">
<label>{{form.ipaddr.label}}</label>
</div>
<div class="col-4">
<div class="input-group">
{{form.ipaddr}}
<div class="input-group-append">
<button class="btn btn-success add-form-row">+</button>
</div>
<div class="col-2">
<p id="cekip"></p>
</div>
</div>
</div>
</div>
</div>
{% endfor %}
Javascript:
function updateElementIndex(el, prefix, ndx) {
var id_regex = new RegExp('(' + prefix + '-\\d+)');
var replacement = prefix + '-' + ndx;
if ($(el).attr("for")) $(el).attr("for",
$(el).attr("for").replace(id_regex, replacement));
if (el.id) el.id = el.id.replace(id_regex, replacement);
if (el.name) el.name = el.name.replace(id_regex, replacement);
}
function cloneMore(selector, prefix) {
var newElement = $(selector).clone(true);
var total = $('#id_' + prefix + '-TOTAL_FORMS').val();
newElement.find(':input').each(function() {
var name = $(this).attr('name')
if(name) {
name = name.replace('-' + (total-1) + '-', '-' + total + '-');
var id = 'id_' + name;
$(this).attr({'name': name, 'id': id}).val('').removeAttr('checked');
}
});
total++;
$('#id_' + prefix + '-TOTAL_FORMS').val(total);
$(selector).after(newElement);
var conditionRow = $('.form-row:not(:last)');
conditionRow.find('.btn.add-form-row')
.removeClass('btn-success').addClass('btn-danger')
.removeClass('add-form-row').addClass('remove-form-row')
.html('-');
return false;
}
function deleteForm(prefix, btn) {
var total = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val());
if (total > 1){
btn.closest('.form-row').remove();
var forms = $('.form-row');
$('#id_' + prefix + '-TOTAL_FORMS').val(forms.length);
for (var i=0, formCount=forms.length; i<formCount; i++) {
$(forms.get(i)).find(':input').each(function() {
updateElementIndex(this, prefix, i);
});
}
}
return false;
}
$(document).on('click', '.add-form-row', function(e){
e.preventDefault();
cloneMore('.form-row:last', 'form');
return false;
});
$(document).on('click', '.remove-form-row', function(e){
e.preventDefault();
deleteForm('form', $(this));
return false;
});
another js :
$(document).ready(function() {
$('input#id_form-0-ipaddr').keypress(function() {
var _this = $(this);
setTimeout(function() {
//ajax ..
}, 3000);
});
});
the field and field id like this
[ipaddress input field][+] => input id = form-0-ipaddr
[ipaddress input field][+] => input id = form-1-ipaddr
[ipaddress input field][+] => input id = form-2-ipaddr
[+] = add button, every time add form, the input id increase
its just send the first field
As i dont have information on your project, i want to give you an example that you can use.
Create a forms.py if you dont have one
from django.forms import formset_factory
from django import forms
class IPForm(forms.Form):
ipaddr= forms.CharField(
widget=forms.TextInput(attrs={
'class': 'form-control',
})
)
IPFormset = formset_factory(IPForm, extra=1)
Extra could be 100- based on the number of forms you want on your browser(view)
Then in your views.py, import IPFormset
from .forms import IPFormset
from .models import YourModel
So use IPFormset in place of your normal formclass you have here before. and return it as ipform
And in your template(html page)
<form class="form-horizontal" method="POST" action="">
{% csrf_token %}
{% for form in ipform %}
<div class="form-group">
<div class="row form-row spacer">
<div class="col-2">
<label>{{form.ipaddr.label}}</label>
</div>
<div class="col-4">
<div class="input-group">
{{form.ipaddr}}
<div class="input-group-append">
<button class="btn btn-success add-form-row">+</button>
</div>
<div class="col-2">
<p id="cekip"></p>
</div>
</div>
</div>
</div>
</div>
{%endfor%}
And you could look into django formset
https://docs.djangoproject.com/en/2.1/topics/forms/formsets/
for better explanation
I am trying to have an input field in the template that the user enters a query and that query goes to the views.py
and from there i m taking the query and pass it as argument to the bash script.
This is what i have for now.
views.py
def home(request):
if request.method == 'POST':
try:
query = request.POST['query']
test = subprocess.check_call(['home/.../bash.sh',
query])
return render(request, 'base.html', {'input': test})
except KeyError:
return HttpResponse("Nothing was submitted!")
base.html
<form action="/" method="post">
{% csrf_token %}
<input type="hidden" name="query" value="{{ input }}">
<input type="submit" value="Submit">
</form>
I am stuck right here..i don't know if i shout request.POST or something else much simpler...cause i don't want to use a form.
I figure it out by creating a script in the html template.
<script>
$(".opener").click(function () {
var thead = $("#mytable").find("thead");
thead.find('th').last().remove();
thead = thead.html();
var row = $(this).parents('tr');
row.find('td').last().remove();
row = row.html();
var table = $(document.createElement('table'));
table.append('<thead>' + thead + '</thead>');
table.append('<tbody><tr>' + row + '</tr></tbody>')
$(".modal").html("").append(table);
$(".modal").dialog({width: 'auto', position: 'top'});
});
</script>
I'm trying to do a inline formset with UI not with django built in inlineformset_factory form. Here I'm done with add_view and edit_view. Here in the edit view I can update the existing record for the both parent and child model,and can add new record to the child model. But I cant remove the existing record from the child model in inline formset.Every thing is fine working at client side. When I click remove button from the UI, the record is removed by javascript, But in server side, in the edit_view the #Delete Existing record block cloud take the delete/remove functionality. I tried in many possible ways but I can't make the delete query for the removed items form the client side.
models.py
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=128)
def __unicode__(self):
return self.name
class Product(models.Model):
category = models.ForeignKey(Category)
name = models.CharField(max_length=128)
price = models.CharField(max_length=128)
views.py
def add(request):
context = RequestContext(request)
if request.method == 'POST':
category = Category.objects.create(name = request.POST['category'])
try:
for n in range(1,7):
product = Product.objects.create(category= category,name=request.POST['name_'+str(n)],price=request.POST['price_'+str(n)])
except KeyError:
pass
return HttpResponseRedirect('/')
return render_to_response('add.html',context)
def edit(request,pk):
category = get_object_or_404(Category,id=pk)
product = Product.objects.filter(category=category)
product_count = product.count()
context = RequestContext(request)
if request.method == 'POST':
for c in Category.objects.filter(id = category.id):
c.name = request.POST['category']
c.save()
try:
#Update Existing record(child)
for p,n in zip(Product.objects.filter(category = c),range(1,7)):
p.name = request.POST['name_'+str(n)]
p.price = request.POST['price_'+str(n)]
p.save()
except KeyError:
#Delete Existing record(child)
try:
for d in range(1,7):
for i in Product.objects.all().filter(name=request.POST.get('name_'+str(d)),price=request.POST.get('price_'+str(d))):
print i.name
except KeyError:
pass
else:
#Add new record(child)
try:
for r in range(1,7):
product,created = Product.objects.update_or_create(category= category,name=request.POST['name_'+str(r)],price=request.POST['price_'+str(r)])
except KeyError:
pass
return HttpResponseRedirect('/')
args = {'category':category,'product':product,'product_count':product_count}
return render_to_response('edit.html',args,context)
add.html
<h1>Add</h1>
<script type="text/javascript">
var i = 1;
function addProduct(){
if (i <= 5){
i++;
var div = document.createElement('div');
div.innerHTML = 'Name:<input type="text" name="name_'+i+'" >Price:<input type="text" name="price_'+i+'" ><input type="button" value="-" onclick="removeProduct(this)">';
document.getElementById('products').appendChild(div);
}
}
function removeProduct(div) {
document.getElementById('products').removeChild( div.parentNode );
i--;
}
</script>
<form method="post" action="/add/">{% csrf_token %}
<label>Category</label>
<div>
<input type="text" name="category">
</div>
<label>Product</label>
<div id="products">
<input type="button" id="add_product()" onClick="addProduct()" value="+" />(limit 6)<br>
Name:<input type="text" name="name_1">Price:<input type="text" name="price_1">
</div>
<div>
<input type="submit" value="Submit">
</div>
</form>
edit.html
<h1>Edit</h1>
<script type="text/javascript">
var i = {{product_count}};
function addProduct(){
if (i <= 5){
i++;
var div = document.createElement('div');
div.innerHTML = 'Name:<input type="text" name="name_'+i+'" >Price:<input type="text" name="price_'+i+'" ><input type="button" value="-" onclick="removeProduct(this)">';
document.getElementById('products').appendChild(div);
}
}
function removeProduct(div) {
document.getElementById('products').removeChild( div.parentNode );
i--;
}
</script>
<form method="post" action="/edit/{{category.id}}/">{% csrf_token %}
<label>Category</label>
<div>
<input type="text" name="category" value="{{category}}">
</div>
<label>Product</label>
<div id="products">
<input type="button" id="add_product()" onClick="addProduct()" value="+" />(limit 6)
{% for list in product %}
<div>
Name:<input type="text" name="name_{{ forloop.counter }}" value="{{list.name}}">Price:<input type="text" name="price_{{ forloop.counter }}" value="{{list.price}}"><input type="button" value="-" onclick="removeProduct(this)">
</div>
{% endfor %}
</div>
<div>
<input type="submit" value="Submit">
</div>
</form>