Printing New Page with Python CGI - python

I'm using/learning Python to do a CGI assignment. Basically we have to present some forms, and then based on user input, present different forms, etc.
This is my script code so far:
import cgi
import cgitb
cgitb.enable() # for troubleshooting
print ("Content-type: text/html\n\n")
form1 = open("html/assg5form1.html")
form2 = open("html/assg5form2.html")
form3 = open("html/assg5form3.html")
form4 = open("html/assg5form4.html")
form5 = open("html/assg5form5.html")
formstring = form1.read()
print formstring
The issue that I'm having is after presenting that first form, I don't know how to handle the input the user gives. I would normally attach an action to the form and fire another script, but we are required to do all of our scripting within one file. How can I clear out the form that I've shown and show another one?

Related

Run Python script in Django template through a button

I have a very small project in Django where I get fx_rates through a Python script (details below). These are used to convert amounts in different currencies to GBP. I would like to know how I can just have a button on the website that allows to refresh this query instead of having to run it manually in the IDE. Can I create a view for this? How would I show this in a template? Thanks
fx_rates.py
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE','fx_rates_project.settings')
import django
django.setup()
from fx_rates_app.models import fx_table
import pandas_datareader.data as web
from datetime import datetime
os.environ["ALPHAVANTAGE_API_KEY"] = '#########'
fx_gbp_to_eur = web.DataReader("GBP/EUR","av-forex")
eur = float(fx_gbp_to_eur[4:5].values[0][0])
fx_gbp_to_aud = web.DataReader("GBP/AUD","av-forex")
aud = float(fx_gbp_to_aud[4:5].values[0][0])
fx_gbp_to_usd = web.DataReader("GBP/USD","av-forex")
usd = float(fx_gbp_to_usd[4:5].values[0][0])
from datetime import datetime
now = datetime.now()
dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
webpg1 = fx_table.objects.get_or_create(eur_to_gbp=eur,aud_to_gbp=aud,usd_to_gbp=usd,date_time=dt_string)[0]
In the template I included:
<form method="post">
{% csrf_token %}
<button type="submit" name="run_script">Refresh</button>
</form>
However, I don't think the best way to do this would be to copy the all script in views with request.POST. Is there another way to leave the script in another file and just create a view to run it (e.g. if request.method == 'POST' run fx_rates.py)?
This can be definitely done by creating a function update_fx to wrap your script and then call that function in your view.
Now for the tricky part.
Do you need the values to render them or just to update them?
Rendering will be easy, just return them from your function and you will
be able to use them in your template.
This though includes the waiting time to fetch these values. When your view will be executed you will have to wait for the function to fetch the values.
The alternative is to "trigger" a second job that updates the values from your
view. This pattern is called a task queue and there are many solutions that you can leverage already, depending on how complicated things should be (what happens if the job has an error? how many times should we retry? ...).
This also has the unfortunate effect that now you run a second python script somewhere that listens for new tasks and executes them.
As always your choice is based on tradeoffs, personally if the server has good internet connection and the request is completed fast I would not mind putting it
in my view as is.
Hope this is helpful.
Let's see an example
# update.py
from fx_rates_app.models import fx_table
import pandas_datareader.data as web
from django.conf import settings
from datetime import datetime
import os
def get_price():
os.environ["ALPHAVANTAGE_API_KEY"] = '#########'
fx_gbp_to_eur = web.DataReader("GBP/EUR","av-forex") # here we are reading stuff from the network I guess
eur = float(fx_gbp_to_eur[4:5].values[0][0])
fx_gbp_to_aud = web.DataReader("GBP/AUD","av-forex")
aud = float(fx_gbp_to_aud[4:5].values[0][0])
fx_gbp_to_usd = web.DataReader("GBP/USD","av-forex")
usd = float(fx_gbp_to_usd[4:5].values[0][0])
now = datetime.now()
dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
# here you have two choices,
# either you return the raw values
# or you put them into a model
return {
'timestamp': dt_string,
'value': 1,
'currency': 'gbp',
'eur': eur,
'aud': aud,
'us': us,
}
webpg1 = fx_table.objects.get_or_create(eur_to_gbp=eur,aud_to_gbp=aud,usd_to_gbp=usd,date_time=dt_string)[0]
return webpg1
# views.py
from django.http import HttpResponse
from update import get_price
def refresh_from_values(request):
data = get_price() # here we don't have a model, just data
webpg1 = fx_table.objects.get_or_create(
eur_to_gbp=data['eur'],
aud_to_gbp=data['aud'],
usd_to_gbp=data['usd'],
date_time=data['timestamp'],
)[0]
# here your render the model using the template
def refresh_from_model(request):
fx = get_price() # here we get back the model instead
# you can render again the model as you can refresh the page
In the future you might be interested in running this thing continuously
and then you would have to move to an event driven app which is more compilicated but can be very satisfying to get right. In django everything
would start with signals and more likely you would have to write some javascript to
update part of the page without refreshing it.

Flask - render page without return

I'm working on an application, where user fills in form.
One of the fields asks for postcode. When request is sent, a separate thread runs python code using PYQT5, rendering page and scraping web, (don't want to pay for API from google) providing mileage between given postcode and set postcode. Results of this thread are saved in a file.
What i would like to do is to open a new webpage with information that the data is being checked. This page would run python code, which checks for results in a file (that takes up to few seconds) using while loop. if the result is in the file, the page redirect to another page.
Is there a way to render a page (or redirect to another page) without using RETURN? i understand that when I use return render_templates (page), rest of the code is ignored.
#app.route('/add_user', methods=['GET', 'POST'])
def add_user():
file = open('app/results_from_g.txt','w')
file.write('')
file.close()
form = AddForm()
if form.validate_on_submit():
url = 'https://google.co.uk/maps/dir/...'
def sendtogoogle(url):
os.system('python googlemaps_mileage.py ' +url)
thread1=threading.Thread(target=sendtogoogle, args=(url,))
thread1.start()
the next line of the code should be redirect to another page, and when results are in the file, either back here, or different page:
while result_from_file==0:
file = open('results_from_g.txt','r')
result_from_file = file.read()
if result_from_file =='': #means no data saved in the file yet
time.sleep(1)
elif wynik =='0': #means wrong postcode
//render page 'wrong postcode'
else:
//render page 'correct postcode

How do you call a python function instead of a script using a form?

I've been reading the book 'Head First Python' where the writer talks about creating dynamic webpages using a module he created called 'yate', an HTML template engine (which I renamed to site_yate in the code below). The example he works through is a hypothetical coach wanting his athletes to be able to check their times online. The design is as follows: first you enter the homepage which has a link to run a script which generates a webpage where you can select the athlete whose times you want to view. Then when you select your athlete and click submit the form calls another script called "site_generate_timing_data.py" where you can views the athlete's top times. So I decided to take it further and add functionality to add a time for the athlete, using this extra line of code in my python script.
print(site_yate.do_form("addtime.py", [athlete_id]))
The HTML this will generate will be this:
<form action="addtime.py" method="POST">
<h1>Want to add a time?</h1>
<input type="Text" name="1" size=40> //"1" is the athlete's id in this example
<input type="Submit" value="Submit">
</form>
As you can see this code calls the script 'addtime.py' which has the following code:
import cgi
import sqlite3
data = cgi.FieldStorage().value[0] #this attribute will be in the form MininFieldStorage(name, value)
id = data.name #this attribute is the input's name i.e. athlete's id
time = data.value #this attribute is the input's value i.e. the time
connection = sqlite3.connect("NUACDB.sqlite") #my DB's name
cursor = connection.cursor()
cursor.execute("""INSERT INTO timing_data (athlete_id, time)
VALUES (?, ?)""",
(id, time)) #just SQL stuff
connection.commit()
connection.close()
Which works fine, however I want to change a few thing about this, since it leaves the user on a blank page. I could generate some HTML code to provide links to the homepage etc. or even JavaScript code to redirect the user automatically, but I want to keep this script HTML-free so that I can also use it elsewhere.
What I want to do instead is make the script execute on the same page. Not only that, but I would also prefer if I could put the addtime.py code as a function in another module called 'athletemodel.py' and call it form there, i.e. athletemodel.addtime() (or I could do from athletemodel import addtime so I can call the function directly). How can I call a python function using HTML code? I'm aware of the onsubmit="" form attribute but apparently that is for JavaScript functions. Another thing I'm unsure about is whether the data submitted in the form will still be accessible through CGI FieldStorage and hence whether my addtime.py code will still work as it is.
This stuff is so confusing! All help is appreciated.
Not sure if you already had it in mind, but I would use ajax (remember to include the jQuery library). Here's a rough example to get you started if this is what you want. It'll keep them on the same page:
JavaScript file:
$('#submitButtonId').click(function (event) {
event.preventDefault();
$('#submitButtonId').hide();
$('#thinking').show(); //some div with a nice ajax loader gif...
$.ajax({
type: 'POST',
data: $('#formId').serialize(),
url: '/URL_path_to_function',
success: function (data) {
$('#loading').hide();
var response = data.result //now do stuff with your response
}
error: function(error){
console.log('Error')}
});
Python view/function:
import jsonify
if request.method == 'POST':
value = request.form['input value'] #flask...
#Do stuff
return jsonify(result='Some response')

How can one clean the data written before in the form?

I am currently trying out python's web.py module by making a small form. I wrote one, and received input from the user and wrote them to a (mysql) database table. Every thing is fine, except for one issue. When I run the program and write something in one of the form's fields, it persists to the next time I want to write in that field. How can I reset the field after receiving the data?
this is my code:
import web
import MySQLdb
url=('/search', 'search_by_name')
db=web.database(dbn='mysql' ,db='std',user='root', pw='123456')
tmpl=web.template.render('templates/')
class search_by_name:
form=web.form.Form(
web.form.Textbox('username',vpass,web.form.notnull),
web.form.Button('search')
)
def GET(self):
return tmpl.page( self.form)
def POST(self):
form=self.form
if not form.validates():
return tmpl.page(form)
else:
name=form['username'].value
a=db.select('student', where="name=$name", vars=locals())
row=list(a)
if row:
col=row[0]
return tmpl.table(row,col)
else:
return tmpl.message("There isn't student with this name in list")
app=web.application (url,globals())
if __name__=='__main__':
app.run()

How to trigger a python script on the django server for the particular form input?

i want to make a search box on my website. I want the output of the particular searchbox input to be generated by particular file which is mapped on the server for the given output.
for ex:- fib 10
will run fib.py and give the response will be the result of the fib.py
You could use subprocess module to run command and take the output.
Update 1
Example view:
import subprocess
def runCmd(request):
cmd = request.POST.get('cmd')
param = request.POST.get('param')
codeDir = '/path/to/py/file/'
absoluteCodePath = codeDir + cmd + '.py'
result = subprocess.check_output([absoluteCodePath, param])
return result
Why would you want to do that? Just import your file/module and use it, this is the correct way.
Lets say you have this code in fib.py:
def calculate(.....):
#code. ...
return result
Now in you other file, lets say it's views.py just do:
import fib
# this is the search view
def search(request):
if request.method == "POST":
# other code
fib.calculate(param) # where param is the value of the search field
I'm not sure if I understood you correctly.. but no there's no reason to use subprocess and execute a file and get the value returned...

Categories