Flask get data from drop-down into sqlite - javascript

I'm completely new to the flask, and really am completely lost with how to approach this.
<tr>
<th>Anmerkungen</th>
<td type="text" name="kunden_anmerkungen" id="kunden_anmerkungen" ><textarea rows="3" cols="30"></textarea></td><br>
</tr>
<tr>
<th>Lektor</th>
<td>
<select name="lektor" id="lektor">
{% for user in users %}
<option value= "{{ user['username'] }}" name="lektor" id="lektor">{{ user['username'] }}</option>
{% endfor %}
</select>
</td>
</tr>
I try to get the data from the drop-down menu to be inserted into an SQLite database. All other fields in the DP are updated. But the Lektor field can't be read.
kunden_anmerkungen = request.form.get("kunden_anmerkungen")
lektor = request.form.get("lektor")
db.execute("UPDATE kunden SET ...
Any help would be greatly appreciated.

you should add the full code involved to this, however it seems like the issue is between the select and the option tag.
Try this:
<tr>
<th>Anmerkungen</th>
<td type="text" name="kunden_anmerkungen" id="kunden_anmerkungen" ><textarea rows="3" cols="30"></textarea></td><br>
</tr>
<tr>
<th>Lektor</th>
<td>
<select name="lektor" id="lektor">
{% for user in users %}
<option value= "{{ user['username'] }}" id="lektor">{{ user['username'] }}</option>
{% endfor %}
</select>
</td>
</tr>
Basically there is name in the option and name in the 'select' tag which may cause issue.
But again if this doesn't work then add the full code because how you set the Database, the flask app or the HTML may change everything
Also Important, I don't see the tag in the HTML file ?

Related

Pass Javascript Calculations to Django Backend

I have an HTML form where users type in the name of items and value corresponding to it in an input form, which is reflected when the form is submitted to Django backend.
In my HTML form I have included some Javascript so that the total of these values are reflected instantly without refreshing and even before submitting the form.
My goal:
Send the total amount calculated by Javascript in the HTML under id Total
<th scope="col">Total Equipment and Assets</th>
<th scope="col" id="Total"></th>
to the class in the
total_assets= models.IntegerField(null=True, blank=True, verbose_name='Total Assets')
in the Models.py after submitting.
Note that the reason for the question is that the total values are not manually added they are directly calculated using Javascript.
Here is a sample to make things more clear.
Here is the HTML Template:
<tr>
<td>
<input
placeholder="Type in the Equipment and assets"
type="text"
class="form-control"
name="item_1"
id="item_1"
{% if form.is_bound %}value="{{ form.item_1.value }}"{% endif %}/>
{% for err in form.item_1.errors %}
<small class="text-danger mb-2 ml-2">{{ err }}</small>
{% endfor %}
</td>
<td>
<h6 style="float:left; margin-right:5px; margin-top:7px">$</h6>
<input
type="number"
class="form-control w-25 subtotal-group subtotal-group-1"
name="item_1_amount"
id="item_1_amount"
{% if form.is_bound %}value="{{ form.item_1_amount.value }}"{% endif %}/>
{% for err in form.item_1_amount.errors %}
<small class="text-danger mb-2 ml-2">{{ err }}</small>
{% endfor %}
</td>
</tr>
<tr>
<td>
<input
placeholder="Type in the Equipment and assets"
type="text"
class="form-control"
name="item_2"
id="item_2"
{% if form.is_bound %}value="{{ form.item_2.value }}"{% endif %}/>
{% for err in form.item_2.errors %}
<small class="text-danger mb-2 ml-2">{{ err }}</small>
{% endfor %}
</td>
<td>
<h6 style="float:left; margin-right:5px; margin-top:7px">$</h6>
<input
autocomplete="off"
type="number"
class="form-control w-25 subtotal-group subtotal-group-1"
name="item_2_amount"
id="item_2_amount"
{% if form.is_bound %}value="{{ form.item_2_amount.value }}"{% endif %}/>
{% for err in form.item_2_amount.errors %}
<small class="text-danger mb-2 ml-2">{{ err }}</small>
{% endfor %}
</td>
</tr>
Here is the Javacript
<script>
const q=(e,n=document)=>n.querySelector(e);
const qa=(e,n=document)=>n.querySelectorAll(e);
const results={};
console. log(results)
qa('[type="number"].form-control').forEach(input=>input.addEventListener('input',function(e){
results[ this.name ]=Number( this.value );
const resultGroupSet1 = [...qa('.subtotal-group-1')]
.map(s => Number(s.value))
.reduce((a,v) => a+v);
q('th#Total').textContent = resultGroupSet1;
}));
</script>
Here is where the total is reflected in the HTML template
<thead class="table-light">
<tr>
<th scope="col">Total Equipment and Assets</th>
<th scope="col" id="Total"></th>
</tr>
</thead>
Here is the models.py
item_1 = models.CharField(max_length=100,null=True, blank=True, verbose_name='Item 1')
item_1_amount = models.IntegerField(null=True, blank=True, verbose_name='Item 1 Amount')
item_2 = models.CharField(max_length=100,null=True, blank=True, verbose_name='Item 2')
item_2_amount = models.IntegerField(null=True, blank=True, verbose_name='Item 2 Amount')
total_assets = models.IntegerField(null=True, blank=True, verbose_name='Total Assets')
Here is the views:
def add_bp(request):
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = infoForm(request.POST)
# check whether it's valid:
if form.is_valid():
form.save()
b_name = form.cleaned_data.get('bName')
messages.success(request, f'PDF created for {b_name}!')
return redirect('application:core')
# if a GET (or any other method) we'll create a blank form
else:
form = infoForm()
return render(request, 'application/template.html', {'form': form, })
Update html to:
<thead class="table-light">
<tr>
<th scope="col">Total Equipment and Assets</th>
<th scope="col">
<!-- Value which is visible (calculated using JS) -->
<span id="Total"></span>
<!-- Add a hidden input to store value (value calculated and assigned using JS) -->
<input type="hidden" name="total_assets" value="0" id="total_assets">
</th>
</tr>
</thead>
Update script to assign resultGroupSet1 as:
textual content to the span tag with id=Total
value to the hidden input with name=total_assets
// Assign result to span tag which is visible
q('span#Total').textContent = resultGroupSet1;
// Assign result as value to hidden input field with name total_assets
q('input#total_assets').value = resultGroupSet1;
No other changes in views.
As an input field with a name="total_assets" is used, the value will be passed on to the request body and will be accessible at request.POST. Here, as the total_assets field is hidden it is not visible to the users and still the value is available in POST data when form is submitted. So, when form.save() is called the calculated value (using JS) will be saved.
I assumes your question is how to get the value in this element:
<th scope="col" id="Total"></th>
You can just simply add input element in your html code and add the name into it:
<th scope="col"><input id="Total" name="total_assets" value=""></th>
Then in your views.py:
def add_bp(request):
if request.method == 'POST':
form = infoForm(request.POST)
if form.is_valid():
form.save()
You can also manually get the Total:
def add_bp(request):
if request.method == 'POST':
total_assets = request.POST.get("total_assets")
Probably what you are looking for is <input type="hidden" ...>, it's not visible by the end user and it's included in the form submit
Why not do this calculation in Django Backend?
My suggestion is to pass all the arguments normally and just add a listener to the model saving (every time you will save an element to the table this little piece of code will run right before it saves it):
from django.db.models.signals import pre_save
from django.dispatch import receiver
#receiver(pre_save, model_class)
def form_pre_save(instance, *args, **kwargs):
instance.total_assets = instance.item_1_amount + instance.item_2_amount
This way when you want to save this kind of element in a different place (in the backend for example) you won't have to re-write the code that does that, but rather just save the instance.
You can read more about the signals pre_save function here

Flask does not return db query when I use the JS hide/unhide. Works if I comment out JS

I am trying to retrieve data from the database based on a users search results. The results, in a table format, should only be shown after the user hits the search button.
Query executes fine when javascript is cancelled out and the table "list" display is changed to block. However, when I enable the javascript I get no results.
<div style="text-align: center;">
{% from "_formhelpers.html" import render_field %}
<form method=post action="/">
<dl style="display: inline-block; text:white;" >{{render_field(form.search)}} </dl>
<button id="searchbutton" type="submit" style="display: inline-block;" class="btn btn-outline-success my-2 my-sm-0" onclick="fetchlist(); return false;">Search</button>
<br>
{% if error %}
<p class = "error"><strong>Error:</strong>{{error}}</p>
{% endif %}
</form>
</div>
<div style="text-align:center;">
<table id="list" style="display:none;" class = "table table-hover" >
<thead>
<th scope="col">First</th>
<th scope="col">Last</th>
<th scope="col">Rating</th>
<th scope="col">Review</th>
</thead>
<tbody>
{% for row in data %}
<tr>
{% for d in row %}
<td>{{ d }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
</body>
<script>
function fetchlist() {
if (document.getElementById('searchbutton').onclick) {
document.getElementById('list').style.display = 'inline';
}
else document.getElementById('list').style.display = 'inline';
}
</script>
{% endblock %}
</html>
#app.route('/', methods=['GET', 'POST'])
def homepage():
try:
form=SearchForm(request.form)
global d1
d1 =""
if request.method == "POST" and form.validate():
search = form.search.data
a = search.split(" ",1)
firstname, lastname = (a[0], a[1])
c,conn = connection()
qry = "SELECT FirstName, LastName FROM posts WHERE FirstName LIKE (%s) AND LastName like (%s)"
c.execute(qry, ((thwart(firstname)), (thwart(lastname))))
d1 = c.fetchall()
c.close()
conn.close()
else: print('error')
return render_template("index.html", data=d1, form = form)
except Exception as e:
return(str(e))
As you already know the problem is caused by your JS. This is because the JS is waiting for the search button to be clicked before it changes the style of the list to inline.
This all seems fine, but the problem comes in the fact that the JS is executed when the button is clicked. But then the request is posted to the server and a new page is sent to the browser with the search results. However, this new page the search button has never been clicked.
You can fix writing the method to display the results into your template. For instance you could wrap the table in an if statement like this...
{% if data|length %}
<div style="text-align:center;">
<table id="list" style="display:none;" class = "table table-hover" >
<thead>
<th scope="col">First</th>
<th scope="col">Last</th>
<th scope="col">Rating</th>
<th scope="col">Review</th>
</thead>
<tbody>
{% for row in data %}
<tr>
{% for d in row %}
<td>{{ d }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table
</div>
{% endif %}
The |length filter makes sure data is not an empty string. Otherwise I believe it may always be true. You could try {% if data %} to double check. It may work.
There are a lot more options....
You could wrap you <script> in the if statement. You should modify it a little. So it does not wait of the search button to be clicked.
You could wrap the inline style in the if statement. Of course you could use CSS classes instead of inline styling. This would be cleaner.

jQuery datetimepicker- unable to select date from next year

I am working on a Python/ Django project, and one of the forms on a webpage has a datetimepicker field on which the user can select a date/ time from the drop-down that appears when the field is selected.
The problem that I currently have is that although the calendar displays a full month at a time, and the user can move through months/ years at a time by selecting next/ previous month, or choosing the year from a drop down inside the calendar, if they move to a month beyond the end of this year, then none of the dates are available for selection.
Having Google'd datetimepicker, it seems that this is a jQuery function, and I want to make sure that there is no value for its maxDate attribute- I've looked through jquery.datetimepicker.full.js, and although it's referenced there, it doesn't see to be given a value at all... so I can't see why this field is not allowing me to select a date beyond the end of this year... anyone have any ideas?
The view that is rendering this page is:
def concept(request, project_id):
project = Project.objects.prefetch_related('budget_versions').get(id=project_id)
deposit = Deposit.objects.get_or_create(project=project)[0]
presentations = project.budget_versions.select_related('meeting').prefetch_related('budget_items', 'cci_items', 'presenters').filter(version_number__isnull=False).annotate(vn=F('version_number') * -1).order_by('presentation_date', 'created', '-vn')
end_details = EndDetails.objects.get_or_create(project=project)[0]
presentation_formset = BudgetPresentationFormset(prefix="presentations", instance=project, queryset=presentations)
drawing_formset = DrawingUploadFormset(prefix="drawings", queryset=Drawing.objects.filter(budget__in=presentations).order_by('budget__presentation_date', 'budget__created'))
context = {
'project': project,
'presentations': presentations,
'presentation_formset': presentation_formset,
'drawing_formset': drawing_formset,
'deposit_form': DepositInfoForm(instance=deposit),
'ended_form': EndDetailsForm(instance=end_details),
'budget_notes_form': BudgetNotesForm(instance=project.budget_overview),
}
return render(request, 'projects/concept.html', context)
and the Django that is displaying the form on which the 'date' field is displayed is:
{% if not forloop.last and presentation_form.instance.budget_items.count %}
<tr class="split-rows">
<td colspan="3">Exc VAT {% if not presentation_form.instance.current_marker %}{{presentation_form.instance.grand_total_exc_vat|money:'£'}}{% else %}{{project.budget_overview.updated_exc_vat|money:'£'}}{% endif %}</td>
<td colspan="3">Inc VAT {% if not presentation_form.instance.current_marker %}{{presentation_form.instance.grand_total_inc_vat|money:'£'}}{% else %}{{project.budget_overview.updated_inc_vat|money:'£'}}{% endif %}</td>
</tr>
{% endif %}
<tr>
{% for hidden in presentation_form.hidden_fields %}
<td class="hidden">{{ hidden }}</td>
{% endfor %}
</tr>
{% for field in presentation_form.visible_fields %}
<tr class="split-rows">
{% if not field.name == 'pdf_package_dep' %}
<td colspan="6"><label>{{field.label}}</label></td>
{% endif %}
</tr>
<tr class="split-rows">
<td colspan="6">
{% if not field.name == 'pdf_package_dep' %}
{% if field.name == 'presentation_date' %}
{% with presentation_form.instance.meeting as meeting %}
{% include "projects/includes/meeting_bit.html" with employee=request.user.employee meeting=meeting UID=presentation_form.instance.id %}
{% endwith %}
{# <a class="ical_trigger button" data-view-url="{% url 'events:add_to_cal' %}" {% if not field.value %}style="display:none"{% endif %}>Add to calendar</a> #}
{% else %}
{{field}}
{% endif %}
{% endif %}
</td>
</tr>
{% endfor %}
Edit
It would appear that what's actually displaying the calendar is the HTML file included by the line:
{% include "projects/includes/meeting_bit.html" with employee=request.user.employee meeting=meeting UID=presentation_form.instance.id %}
The meeting_bit.html file has the following code:
{% if meeting and meeting.event_creator and meeting.event_creator != employee %}
<table>
<tr>
<td>
{{meeting.date|date:"d/m/Y H:i"}}<br>
</td>
<td rowspan="2"><a class="change_event_organiser" data-view-url="{% url 'events:change_event_creator' meeting.id %}" class="button">Edit</a></td>
</tr>
<tr>
<td class="text-sm">
Organised by {{meeting.event_creator}}
</td>
</tr>
</table>
{% else %}
<div id="cal_{{field.name}}_{{UID}}">
{{field}}
<a class="ical_trigger button" data-view-url="{% url 'events:add_to_cal' %}" {% if not field.value %}style="display:none"{% endif %}>
{% if meeting.event_id %}Update calendar event{% else %}Add to calendar{% endif %}
</a>
</div>
{% endif %}
I can see when I 'inspect' the date field of the form in the browser, that it is in a div which has an ID in the format cal_{{field.name}}_{{UID}}, so I know that this is where the calendar is initialised/ displayed... But I can't see anything that is restricting the available options for selection to dates from this year only... why can't I select a date from next year, or any other year in the future?

Getting post data from html table inside a form? Django

I have a dynamically populated html table that can be edited by an user (they can add rows delete them, etc -this is managed through javascript-).
The problem is, even when the table is inside the form, the server doesn't get any post data from it.
Here is the code for the template:
{% extends 'base.html' %}
{% block content %}
<script>
function add_row(){
var table = document.getElementById("body");
var row = table.insertRow(table.rows + 1);
var cell = row.insertCell(0);
var combo1 = document.createElement("select");
var option;
{% for opt in options_all %}
option = document.createElement("option");
option.setAttribute("value", "{{ opt.id }}");
option.text="{{ opt.description }}";
combo1.add(opcion);
{% endfor %}
cell.appendChild(combo1);
}
</script>
<form action='.' method='post'>
{% csrf_token %}
{{ form.as_p }}
<input type="button" value="New row" onclick="add_row()">
<table id="table_id">
<thead>
<tr>
<th>
Options
</th>
</tr>
</thead>
<tbody id="body">
</tbody>
</table>
<input type='submit' value='Submit'>
</form>
{% endblock %}
How can I get the data from the select elements?? Thanks!!
Edit: I have checked the request element and request.post doesn't have the desired data
SOLVED.
You have to specify a name for each select element inside the table. (Not the option elements)

Show button in Django template only when the file is selected through check box?

I am getting the check box dynamically in Django template like this:
<td><input type="checkbox" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" /></td>
<td><label for="choice{{ forloop.counter }}">{{ choice.file_name }}</label></td>
There's a unshare button like this:
<button>Unshare</button>
I want to show the Unshare button only when the user clicks on check-box.
Firstly add some more id's to your template so that you can identify elements.
<table id="choices">
{% for choice in choices %}
<td><input type="checkbox" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" /></td>
<td><label for="choice{{ forloop.counter }}">{{ choice.file_name }}</label></td>
{% endfor %}
</table>
Then give the button an id and an inline style -
<button id="unshare_button" style="display: none;">Unshare</button>
Then use the following javascript (this shows the button as soon as any one of the
checkboxes is clicked - it doesn't hide the button if they're unchecked).
var choices_table = document.getElementByID('choices');
var checkboxes = choices_table.getElementsByTagName('input');
var unshare_button = document.getElementByID('unshare_button');
for (var i = checkboxes.length; i > 0; i--) {
checkboxes[i].addEventListener('click', function() {
unshare_button.style.display = 'inline';
}
}
I'm afraid I haven't checked this code, but it should give you an idea.

Categories

Resources