Send data from Javascript → Python and back without reloading the page - javascript

I'm trying to make a stock finance like website where anyone can get fake money and buy stocks. So in the buy page, I am trying to implement a feature where as the user types the stock symbol and the number of shares, in real time, the pricing shows up in the h1 tags that have an id of "render". This can be achived if user input is sent to my app.py and after looking up the price using an api and some math, app.py send the price back to javascript to update the page.
I've been trying to use fetch() and AJAX but I don't understand any of the tutorials or stack overflow questions. Can someone give me a reliable solution and explain it to me?
HTML:
{% extends "layout.html" %}
{% block title %}Buy{% endblock %}
{% block main %}
<form action="/buy" method="post">
<div class="mb-3">
<input class="form-control mx-auto w-auto" autocomplete="off" name="symbol" placeholder="Symbol" value="{{ input_value }}" id="symbols">
</div>
<div class="mb-3">
<input class="form-control mx-auto w-auto" autocomplete="off" autofocus name="shares" placeholder="Shares" id="shares">
</div>
<div class="mb-3">
<button class="btn btn-primary" type="submit">Buy</button>
</div>
</form>
<h1 id="render">
</h1>
<script>
</script>
{% endblock %}
App.py:
#app.route("/buy", methods=["GET", "POST"])
#login_required
def buy():
"""Buy shares of stock"""
if request.method == "GET":
return render_template("buy.html", input_value = "")
else:
return render_template("buy.html", input_value = request.form.get("symbol"))
I'm trying to use the function above for rendering the template
Accepting response and sending back information:
#app.route("/show_price", methods=["GET", "POST"])
def show_price():
#logic stuff
return #price

TL;DR at bottom
I found a solution to the problem by using this as my app.py:
#app.route("/show_price", methods=["GET", "POST"])
#login_required
def show_price():
# https://www.makeuseof.com/tag/python-javascript-communicate-json/
data = request.get_json()
if data[1].isdigit() == True:
data = jsonify() # the data
return data
else:
return ""
and using fetch() in my javascript:
{% extends "layout.html" %}
{% block title %}Buy{% endblock %}
{% block main %}
<form action="/buy" method="post">
<div class="mb-3">
<input id="symbols">
</div>
<div class="mb-3">
<input id="shares">
</div>
<h2 id="render">
</h2>
<div class="mb-3">
<button class="btn btn-primary" type="submit">Buy</button>
</div>
</form>
<script>
let input1 = document.getElementById('symbols');
let input = document.getElementById('shares');
input.addEventListener('keyup', function(event) {
value = [
input1.value, input.value
]
fetch("http://127.0.0.1:5000/show_price",
{
method: 'POST',
headers: {
'Content-type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify(value)}).then(res =>{
if(res.ok){
return res.json()
} else {
document.querySelector('h2').innerHTML = "Keep typing...";
}
}).then(jsonResponse=>{
word = "That would be " + jsonResponse
document.querySelector('h2').innerHTML = word;
})
.catch((err) => console.error(err));
});
</script>
{% endblock %}
so as the user is typing in the the shares field the event listener will get the symbols and shares fields, use fetch() to get the data over to def show_price() with a jsonified array of symbol and shares. If there is an error the div id="render" will display "Keep typing". After python gets the information it will look it up using a function, then it will return the price of the shares in json format. Then javascript will get the data and use some javascript to change the html.
TL;DR
Basically I used fetch() to get the data to python, did some algorithm stuff and python return it to javascript. https://www.makeuseof.com/tag/python-javascript-communicate-json/ is really useful in teaching you how to use fetch().

Related

How do I send data from javascript to python flask back-end?

I know this question has been answered already but I do not understand.
I am new to flask and co-developing a chat website.
This includes a database for users to log in
My signup.html has a considerable size, so I will only include the part I'm having troubles with:
{% extends "base.html" %}
{% block title %} Sign up {% endblock %}
{% block content %}
<form method="POST" id="signupform" action="#" onsubmit="checkForm()">
<div class="form-group row">
<div class="col-sm-10">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="gridCheck1">
<label class="form-check-label" for="gridCheck1">
I have read and agreed to the Terms Of Service
</label>
<small id="checkSmall" class="form-text text-muted"></small>
</div>
</div>
</div>
</form>
{% endblock %}
My javascript:
function checkForm() {
var isChecked = document.getElementById("gridCheck1").checked
if (isChecked == false) {
console.warn("TOS not agreed to")
document.getElementById("checkSmall").innerHTML = "Please agree to the TOS before continuing.";
} else {
console.log("Tos were agreed to")
}
}
My python (again, not the whole file):
#app.route("/signup", methods=["GET", "POST"])
def signup():
if request.method == "POST":
Name = request.form["Name"]
Email = request.form["Email"]
Password = request.form["Password"]
usr = users(Name, Email, Password)
acc = [Name, Email, Password]
for value in acc:
if len(value) == 0 or " "*len(value) == value:
flash(f"{value} cant be blank")
return redirect(url_for("signup"))
break
elif len(value) > 100:
flash(f"{value} cant be more then 100 chars")
return redirect(url_for("signup"))
break
db.session.add(usr)
db.session.commit()
flash("Signed up.")
return redirect(url_for('home'))
return render_template("signup.html")
I dont want to redirect to the home page unless the user actually agrees.
I already have the javascript set up to pop a little message if they dont check that checkbox, and I need to tell the server to stop from the js.
Could anyone help?
PS: I could also use another way to acheive my goal.
Also, just in case this can help anyone solve my problem, I'm using bootstrap. I'm not good at html, so anything helps.
Simplest way I can think of (I think this will work; anyone correct me if it is wrong):
<input class="form-check-input" type="checkbox" id="gridCheck1" required>

Trying to create a printable web page in octobercms

Hi I am trying to create a printable page from data send by a form in octobercms
I have created a plugin component which I have called PrintPageForm
<?php namespace Acme\PrintPage\Components;
use Cms\Classes\ComponentBase;
use Input;
class PrintPageForm extends ComponentBase
{
public function componentDetails()
{
// TODO: Implement componentDetails() method.
return
[
'name' => 'Print Page Form',
'description' => 'Detail page print form'
];
}
public function onHandleForm()
{
$var =
[
'overview' => Input::get('print_overview'),
'photos' => Input::get('print_photos')
];
I have this in the default htm file
<form action="/print" data-request-data="printpageform::onHandleForm" data-request-validate data-request-flash accept-charset="utf-8" class="form ajax-form">
<h3 class="sub-heading">Print Details</h3>
<p>To build a printer friendly formatted page, please select from the options shown below:</p>
<ul class="print-section">
<li>
<input type="checkbox" class="checkbox-input" value="1" name="print_overview" id="print_overview">
<label class="checkbox-label period" for="print_overview">Overview: Summary and key features alongside a photo of the property.</label>
</li>
<li>
<input type="checkbox" class="checkbox-input" value="1" name="print_photos" id="print_photos">
<label class="checkbox-label period" for="print_photos">Photos: Photo gallery of the property.</label>
</li>
</ul>
<input type="hidden" name="print" value="1">
<button class="btn button-large one-third palm-one-whole" type="submit" rel="print" >Print</button>
</form>
I am trying to access the value of print_overview and print_photo values in my print view page but can not figure out how to access these values I can see these values being passed in Debugbar as follows "request_query
array:2 [ "print_overview" => "1" "print" => "1" ]" and in my view file I have
{%if "print_overview" == "1" %}
{{ 'checked' }}
{% else %}
{{ 'Not Checked' }}
{% endif %}
but it does seem to matter what the value of print_overview is the page only echos out Not Checked I'm in a rut that I can't figure out any thoughts would be gratefully accepted.
Couple of pointers. When rendering a form in Twig, you should use either the {{ form_open() }} or {{ form_ajax() }} tags
Secondly, you can access the request data via the post() function in your component class; and you pass it to your view (the component partial) through the page property. So, your handler would like something like:
public function onHandleForm()
{
// Pass the variables to the view renderer
$this->page['print_overview'] = (bool) post('print_overview');
$this->page['print'] = (bool) post('print');
// Return a partial response http://octobercms.com/docs/ajax/update-partials#pushing-updates
return ['#view-response-element' => $this->makePartial('#response')]; 
}
While your response.htm partial file would look something like this:
{% if print_overview %}
"checked"
{% else %}
"not checked"
{% endif %}
As a note, if you are using the {% macro %} tags, these do not have access to the local scope of the partial file, i.e. they do not have access to the variables provided to the view. Any evaluation done within {% macro %} tags needs to be based on variables passed to it.
The best strategy for printing I find is to use JavaScript:
<!-- Link to print -->
<p>Print this invoice</p>
<!-- Invoice printer -->
<script type="text/template" id="invoiceTemplateContents">
Printable contents go in here
</script>
<!-- Script -->
<script>
function printInvoice() {
var printWindow = window.open('','','left=0,top=0,width=950,height=500,toolbar=0,scrollbars=0,status=0')
printWindow.document.write($('#invoiceTemplateContents').html())
printWindow.document.close()
printWindow.focus()
printWindow.print()
printWindow.close()
}
</script>

Using JavaScript to render forms dynamically in Django

So I am new to Django and a complete novice at JavaScript. I am trying to create a view which renders multiple forms dynamically using JavaScript. Below are two forms that I have created.
class CreateTestForm(forms.ModelForm):
class Meta:
model = Test
fields = ['name', 'test_group', 'description', 'query_text', 'failure_condition', 'status']
def getKey(self):
return "create_test_form"
class VC1Form(CreateTestForm):
expected_relation = forms.ChoiceField(choices = [('<','<'), ('>','>'), ('=','='), ('<=','<='), ('>=','>='), ('!=','!=')], required = True, label = 'Expected Relation: ')
num_rows = forms.IntegerField()
def getKey(self):
return "vc1_form"
In addition, I have the following view
def create_test(request):
context = {
'all_validation_classes': ValidationClass.objects.all()
}
for form in [CreateTestForm, VC1Form]:
if request.method == 'POST':
f=form(request.POST)
if (f.is_valid()):
return HttpResponseRedirect('/test_created/')
else:
return HttpResponseRedirect('/test_not_created/')
else:
f = form()
context[f.getKey()] = f
return render(request, 'create_test.html', context)
And template:
<form action="/tests/create/" method="post">
{% csrf_token %}
{{create_test_form.as_ul}} <br><br>
<select id="validation_classes_id" name="all_validation_classes" onchange="showForm()">
<option value="%">Choose the validation class</option>
{% for val_class in all_validation_classes %}
<option value="{{ val_class.id }}">{{ val_class.id}} {{val_class.name }}</option>
{% endfor %}
</select>
<br><br>
<script>
function showForm(){
var x = document.getElementById("validation_class_id").value;
}
</script>
<input type="submit" value="Submit" />
I am trying to get to a point, where, when the user selects something from the dropdown (validation_classes_id), the view will render the form corresponding to that selection. I have currently included only one additional form VC1Form here but I have written different forms corresponding to each option in the drop down.
I have tried a few things but nothing has worked yet and any help would be appreciated!
Try something this:
document.getElementById('form').querySelectorAll("label").forEach( e =>
{e.prepend(document.createElement("br"));});
Even better would be:
<form id="form" action="login_view" method="post">
{% csrf_token %}
<table>
{{ form }}
</table>
<input type="submit" value="register">

How can I get the <select> tag option chosen by the user using Flask?

I have a form whereby a user uploads a csv file, that csv file is then converted to a pandas dataframe and the column headers automatically populate the <select> tag options in the form.
I then want the user to select the column that they want and I want that column choice saved in a variable using Flask.
However, I'm having trouble retrieving the option that the user then selects from this select tag.
My template code:
<form class="form-horizontal" action="" method="post" enctype="multipart/form-data">
<fieldset>
<legend>Text Analytics</legend>
<div class="form-group form-group-lg">
<label for="inputData" class="col-lg-2 control-label">Choose Data File:</label>
<div class="col-lg-5">
<input type="file" class="form-control" required="required" autofocus="autofocus" name="inputData"/>
</div>
<div class="col-lg-3">
<button class="btn btn-primary" type="submit" name="upload">Upload</button>
</div>
{% if success %}
<div class="alert alert-success">
×
<strong>Success!</strong> {{success}}.
</div>
{% endif %}
{% if error %}
<div class="alert alert-warning">
×
<strong>Error:</strong> {{error}}.
</div>
{% endif %}
</div>
<div class="form-group form-group-lg">
<label for="colSelect" class="col-lg-2 control-label">Select column for analysis:</label>
<div class="col-lg-5">
<select class="form-control" name="colSelect" id="colSelect">
{% for column in columns %}
<option id="{{column}}">{{column}}</option>
{% endfor %}
</select>
</div>
My Flask code:
#app.route('/textanalytics', methods = ['GET', 'POST'])
def upload_file():
error = None
success = None
columns = []
col = None
if request.method == "POST":
if request.files['inputData'] == '':
error = "No file selected"
else:
file = request.files['inputData']
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
success = 'File uploaded'
data = pd.read_csv(os.path.join(app.config['UPLOAD_FOLDER'], filename), header = 0, low_memory = False)
columns = [i for i in data.columns]
col = request.form.get('colSelect')
return render_template('textanalytics.html', success = success, columns = columns, col = col)
elif file and not allowed_file(file.filename):
error = 'Incorrect file type, .csv only'
return render_template('textanalytics.html', error = error)
return render_template('textanalytics.html', error = error, success = success, columns = columns, col = col)
app.add_url_rule('/uploads/<filename>', 'uploaded_file', build_only=True)
app.wsgi_app = SharedDataMiddleware(app.wsgi_app, {'/uploads': app.config['UPLOAD_FOLDER']})
As you can see, I am using request.form.get('colSelect') to retrieve the option but without any luck. It just returns None which is its initialised value.
I have a feeling it has to do with where I am placing that code but I am new to Flask and so could do with some help.
You have to give each option a value.
<option value="{{ column }}">{{ column }}</option>
I managed to figure it out. I took the form and separated it over two pages. So, the File Upload part was in its own form on a page called textform1.html. The uploaded file would be converted to a pandas dataframe and then a new page called textform2.html would be rendered. This page contained just the <select> part in its own form and thus I was then able to capture the selection from the user.

django forms ForeignKey 'value error must be an instance'

I'm trying to port an application with an existing db. I'm using db_column to have django model Foreign Keys correctly while using the existing database names and columns.
models.py
class foo(models.Model):
foo_id = models.AutoField(primary_key=True, blank=False, null=False)
foo_name = models.CharField(max_length=500, blank=True, null=True)
foo_type_lookup = models.ForeignKey('foo_type_lookup', to_field="foo_type_id", db_column="foo_type", blank=True, null=True)
class foo_type_lookup(models.Model):
foo_type_id = models.AutoField(primary_key=True, blank=False, null=False)
foo_type = models.CharField(max_length=500, blank=False, null=False)
The table foo_type_lookup has two rows (ids 0 and 1) for foo_type 'bar' and 'baz'. I'm trying to make a form to add a record in the foo table which will have a foreign key to foo_type_lookup. Foo can either be bar or baz.
views.py
def add_foo(request):
action = '#'
errors = None
if request.method == 'POST':
form = FooForm(request.POST)
if form.is_valid():
form.save(commit=True)
return home(request)
else:
# The supplied form contained errors - just print them to the terminal.
errors = form.errors
else:
# If the request was not a POST, display the form to enter details.
form = FooForm()
# Bad form (or form details), no form supplied...
# Render the form with error messages (if any).
return render(request, 'foo/add_foo.html', {'form' : form, 'errors' : errors, 'action' : action})
forms.py
CONTACT_FOO_CHOICES = [[0,'Bar'],[1,'Baz']]
class FooForm(forms.ModelForm):
foo_type_lookup = forms.ChoiceField(widget=RadioSelect(), choices=CONTACT_FOO_CHOICES)
foo_name = forms.CharField(label='First Name', max_length=500, required=False)
class Meta:
model = foo
fields = ('foo_name','foo_type_lookup')
I have to iterate over the form object in my template so I can add a jQuery function when the radio buttons are changed. I find this pretty clunky, but I'm not sure of a more django way to accomplish this:
add_foo.html
<h2>add_foo.html</h2>
<form action="{{action}}" method="post" role="form">
{% csrf_token %}
{% for field in form %}
{% if field.auto_id = 'id_foo_type_lookup' %}
{% for choice in form.foo_type_lookup.field.choices %}
<li>
<label for="id_{{ field.html_name }}_{{ forloop.counter0 }}">
<input type="radio"
id="id_{{ field.html_name }}_{{ forloop.counter0 }}"
value="{{ choice.0 }}"
{% if choice.0 == '0' %}
checked="true"
{% endif %}
name="{{ field.html_name }}"
onchange="someFunction('id_{{ field.html_name }}_{{ forloop.counter0 }}')"/>
{{ choice.1 }}
</label>
</li>
{% endfor %}
{% else %}
<div class="formfield_err">{{ field.help_text }}</div>
<div id="{{ field.auto_id }}_container" >
<div class="formfield_divlbl">{{ field.label_tag }}
</div>
<div class="formfield_divfld">{{ field }}
{% if field.field.required %}
<span class="required">*</span>
{% endif %}
</div>
<div id="{{ field.auto_id }}_errors">{{ field.errors }}
</div>
</div><div class="clear" style="margin-bottom:12px;"></div>
{% endif %}
{% endfor %}
<input type="submit" value="Submit" />
</form>
I get the error:
Cannot assign "'0'": "foo.foo_type_lookup" must be a "foo_type_lookup" instance.
How do I layout the radio buttons for the type lookup to add onchange javascript and supply my ModelForm with an object of 'foo_type_lookup' so the data will save to the database?
A ChoiceField does not know it needs to coerce the provided value to a particular model instance.
Use a ModelChoiceField instead.
https://docs.djangoproject.com/en/1.7/ref/forms/fields/#modelchoicefield
Whoops, it seems you want some very specific display logic for your values hard coded into your python which may not necessarily equate to your string representations of your related model.
If so, override your form save to apply any coercion there before the real save gets called via super.
You can also manually apply any python logic via commit=False (I notice you already have that statement set to True and perhaps you were playing with the idea.)
obj = form.save(commit=false)
obj.foo_lookup_type = MyObject.objects.get(pk=form.cleaned_data['foo_lookup_type'])
obj.save()

Categories

Resources