Dynamic Loading on Flask Site with Unique URL - javascript

I am building a Flask site that dynamically loads some information like the time but I'm running into some issue with AJAX with jQuery.
Following the example on the flask site https://flask.palletsprojects.com/en/1.1.x/patterns/jquery/
I want to change it to a dynamic URL based on the users unique ID instead of a static one.
Python File:
from flask import Flask, jsonify, render_template, request
app = Flask(__name__)
#app.route('/_add_numbers/<UNIQUEID>')
def add_numbers():
a = request.args.get('a', 0, type=int)
b = request.args.get('b', 0, type=int)
return jsonify(result=a + b)
#app.route('/')
def index():
return render_template('index.html')
The HTML
<script type=text/javascript>
$(function() {
$('a#calculate').bind('click', function() {
$.getJSON($SCRIPT_ROOT + '/_add_numbers/UNIQUEID', {
a: $('input[name="a"]').val(),
b: $('input[name="b"]').val()
}, function(data) {
$("#result").text(data.result);
});
return false;
});
});
</script>
<h1>jQuery Example</h1>
<p><input type=text size=5 name=a> +
<input type=text size=5 name=b> =
<span id=result>?</span>
<p><a href=# id=calculate>calculate server side</a>
I cannot figure out how to put a unique ID into the HTML. Any help is much appreciated!

There are a variety of ways to do this. I would recommend simply adding the user's id into the template context, with render_template("index.html", user_id=current_user.id) (make sure you import current_user from flask. This will return a user id if the user is logged in, and None if not. Then you can do the following:
$(function() {
$("a#calculate").bind("click", function() {
$.getJSON($SCRIPT_ROOT + "/_add_numbers/{{ user_id }}",
etc etc: your code goes here
)}
)}
That should do it.
Alternatively you could actually use the value of current_user.id (if you feel you understand it) in the template, as this is implicitly passed down with Jinja anyway. o substitute {{ user_id }} with `{{ current_user.id }}.

Related

Create a FlaskForm dropdown based on the query string value

class DownloadForm(FlaskForm):
products = service.get_products()
choices = [(product, product.replace('-', ' '))
for product in products]
application = SelectField(
'Application',
[DataRequired()],
choices=choices
submit = SubmitField('Submit')
#home.route('/downloads/<application_name>', methods=['GET', 'POST'])
def downloads():
download_form = DownloadForm()
My route will be downloads/application_name.
Can I send this routevalue "application_name" to the form to filter out the choices in the Download Form?
I'm new to entire flask and python.
You can use a factory function to use the parameter from the URL to do your database query. Based on this query, a form is then created that can be used within the route.
def download_form_factory(name):
products = [
'Archiver',
'Editor-1',
'Editor-2',
'Music-Player',
'Video-Player'
]
class DownloadForm(FlaskForm):
app = SelectField(
'Application',
choices= [
(product, product.replace('-', ' ')) \
for product in filter(lambda p: name.lower() in p.lower(), products)
]
)
submit = SubmitField('Download')
return DownloadForm
The following example uses an input field of type QuerySelectField from WTForms-SQLAlchemy to facilitate database queries. As you can see above, the functionality is also possible with a normal SelectField.
A number of products are added to the database which, in addition to their name, have an additional property build.
If the user selects a name on the index page, all products that have the selected name are available for selection. He can then choose between the offered versions.
The form is created inside a function. The name to be searched for is passed to this function as a parameter. This can then be used to create the database query.
def download_form_factory(name):
# Create a class of the form.
class DownloadForm(FlaskForm):
# Create the select field
app = QuerySelectField(
# with a label
'Application',
# and the database entries containing the given name as options
query_factory=lambda: Product.query.filter(Product.name.ilike(f'%{name}%')).all(),
# and a label for each of these options.
get_label=lambda p: '%s (Build %s)' % (p.name, p.build),
# An option must be selected by the user.
validators=[InputRequired()]
)
# Create the Submit button.
submit = SubmitField('Download')
# Return the created form class.
return DownloadForm
Within the endpoint, the function mentioned is used and an instance of the form is created, which can be used in the usual way.
#app.route('/download/<string:name>', methods=['GET', 'POST'])
def download(name):
# Create the form and an instance of it.
form = download_form_factory(name)(request.form)
if form.validate_on_submit():
# If the POST request is sent with valid information,
# the form data can be requested.
# The result is the selected database object.
print(form.app.data)
return render_template('download.html', **locals())
Here is the complete example.
Flask (app.py)
from flask import (
Flask,
render_template,
request,
)
from flask_wtf import FlaskForm
from flask_sqlalchemy import SQLAlchemy
from wtforms import SubmitField
from wtforms_sqlalchemy.fields import QuerySelectField
from wtforms.validators import InputRequired
app = Flask(__name__)
app.secret_key = b'your secret here'
db = SQLAlchemy(app)
class Product(db.Model):
__table_args__ = (db.UniqueConstraint('name', 'build'),)
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False)
build = db.Column(db.String, nullable=False)
# Create a class of the form.
def download_form_factory(name):
class DownloadForm(FlaskForm):
app = QuerySelectField(
'Application',
get_label=lambda p: f'{p.name} (Build {p.build})',
query_factory=lambda: Product.query.filter(Product.name.ilike(f'%{name}%')).all(),
validators=[InputRequired()]
)
submit = SubmitField('Download')
return DownloadForm
# Fill the database with sample data.
with app.app_context():
db.drop_all()
db.create_all()
products = [Product(name=f'Product-{str(i).zfill(2)}', build=f'{j}') \
for i in range(1, 21) for j in range(1,i+1)]
db.session.add_all(products)
db.session.commit()
#app.route('/')
def index():
products = Product.query.group_by(Product.name).order_by(Product.name).all()
return render_template('index.html', **locals())
#app.route('/download/<string:name>', methods=['GET', 'POST'])
def download(name):
# Create the final object of the form.
form = download_form_factory(name)(request.form)
if form.validate_on_submit():
# Inquire about the selected product.
print(form.app.data)
return render_template('download.html', **locals())
HTML (templates/index.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Index</title>
</head>
<body>
<ul>
{% for prod in products -%}
<li>{{prod.name}}</li>
{% endfor -%}
</ul>
</body>
</html>
HTML (templates/download.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Download</title>
</head>
<body>
<form method="post">
{{ form.csrf_token }}
<div>
{{ form.app.label }}
{{ form.app() }}
</div>
{{ form.submit() }}
</form>
</body>
</html>

Prevent users from directly accessing url and redirect to login if not logged in Flask

so I have a flask Application, where in the home page I am rendering a login page to sign in. After sign in they get a form to fill. I am also using the username value while they sign in later on in the form submit process.
This is my relevant flask code:
#app.route('/', methods=['GET', 'POST'])
def home():
return render_template('Login_new.html')
#app.route('/login', methods=['POST'])
def logger():
if request.method == 'POST':
global user
user = request.form['username']
passwrd = request.form['password']
if (user=="admin") and (passwrd=="VendorAdmin2021"):
return redirect(url_for("admin.index"))
url = "api for authentication"
response = requests.post(url, json={"username": user,"password": passwrd}, verify=False)
#data = response.json()
print(response.status_code)
if response.status_code == 200:
return redirect(url_for("test"))
else:
flash('Wrong')
return render_template('Login_new.html')
The test url contains the actual form. Here is the Login_new.html file:
<html>
<head>
<link rel="stylesheet" href="/static/style2.css">
<title>Sign in</title>
</head>
<body>
<div class="main">
<p class="sign" align="center">Novartis</p>
<form class="form1" action="/login" method="POST" id="myForm">
<input class="un " type="text" align="center" placeholder="5-2-1 id" name="username">
<input class="pass" type="password" align="center" placeholder="Password" name="password">
<input type="submit" value="Log in" class="submit">
</div>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2#10.12.5/dist/sweetalert2.all.min.js"></script>
{% with messages = get_flashed_messages() %}
{% if messages %}
<script>
var messages = {{ messages | safe }};
if (messages=="Wrong"){
swal.fire({
title:"Invalid id or password!",
text:"Please make sure you are connected to the Company Intranet",
icon:"error",
closeOnConfirm: false
});
}
</script>
{% endif %}
{% endwith %}
</body>
</html>
Everything works fine if the user follows the set procedure, but if they directly enter the test url in the browser, they bypass the login form and subsequently I can't record their username as well.
Similarly for flask-admin url, if they input the admin credentials, they are redirected to admin url, but if they directly put the admin url, they can access it without any credentials.
How can I prevent that?
EDIT:
I tried using session to achieve the desired result, I tried to follow this https://techmonger.github.io/10/flask-simple-authentication/ . This is my code now:
if response.status_code == 200:
session["logged_in"] = True
return redirect(url_for("test"))
else:
flash('Wrong')
return render_template('Login_new.html')
And in the test url:
#app.route('/test')
def test():
if not session.get('logged_in'):
return render_template('Login_new.html')
form = vendorForm()
Now I am getting error that session has no attribute get.
Please help, I have been stuck on this from way too long
You can use your own custom decorator like in flask login module.
Something similar to this,
def login_required(f):
#wraps(f)
def decorated_function(*args, **kwargs):
if session.get('username') is None or session.get('if_logged') is None:
return redirect('/login',code=302)
return f(*args, **kwargs)
return decorated_function
Then use like this in a route which requires login,
#app.route('/', methods=['GET', 'POST'])
#login_required
def home():
#blah_blah
What this does is , whenever you call url '/' ,it calls decorated_function() present inside login_required() wrapper. So put your login logic inside deccorated_function(). Check if the user is logged in using sesion cookie(or whatever method you want), if not logged redirect to login else don't return anything.
Regarding that session.get() error, did you import session from module flask? The syntax seems correct

Displaying the result of ML model on Web page

I am exploring RESTful Flask API and as a learning I have created a small web form in HTML. Please see below the code for HTML.
<!DOCTYPE html>
<html>
<h2>User Input</h2>
<body
<script>
src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js">
</script>
<script src="/static/js/predict.js"></script>
<p>Please enter the Power prices per unit</p>
<form method="get" action='/predict' target ="_blank"
enctype="multipart/form-data">
New Value - 1:<br>
<input type="number" id="New_val_1">
<br>
New Value - 2:<br>
<input type="number" id="New_val_2">
<br><br>
<button id="btnpredict" type="button">Predict</button>
</form>
<p>If you click the "Submit" button, the form-data will be sent to a page
called "/action_page.php".</p>
</body>
</html>'
Please see below the code for predict.js. This is a JQuery AJAX
$(function(){
$('#btnpredict').click(function(){
$.ajax({
url: '/predict',
data: JSON.stringify({userInput: uInput})
type: 'GET',
contentType: 'application/json',
success: function(response){
("#results").text(response.results);
},
error: function(error){
console.log(error);
}
});
});
});
And finally, the app.py code where the above HTML is getting rendered and upon receiving the the values passed on forms ML model is used.
from flask import Flask, redirect, request, render_template,json, Response
import statsmodels.api as sm
import numpy as np
from sklearn.externals import joblib
app = Flask(__name__)
#app.route('/')
#app.route('/home')
def home():
return render_template('index.html')
#app.route('/predict', methods = ['GET'])
def predict():
if request.method=='GET':
X_value_new_1 = request.values.get('New_val_1')
X_value_new_2 = request.values.get('New_val_2')
X_1,X_2 = X_value_new_1,X_value_new_2
testData = np.array([X_1,X_2]).astype(np.float).reshape(-1,1)
testData=sm.add_constant(testData)
pred = Regression_model.predict(testData)
dump = json.dumps({'prediction':list(pred)})
resp = Response(dump,mimetype='application/json')
return resp
return None
def load_model():
global Regression_model
Regression_model = joblib.load('E:/model_file_save')
if __name__ == "__main__":
print("**Starting Server...")
load_model()
app.run(debug=True)
Now the problem:
When I click on Predict button nothing happens. However, if on the address-bar if I write the 'http://localhost:5000/predict?New_val_1=1000&New_val_2=2000' then I get the correct prediction values in JSON format.
How to fix this issue? Is there any problem in JQuery?
Please help.
Best
AR
Read textbox values e.g. $("#tag").val() and concate with ajax url e.g.
predict?New_val_1=1000&New_val_2=2000'
and remove data property. You can also pass values using data property see below link for example.
https://www.codeproject.com/Questions/870797/How-to-pass-textbox-value-to-other-page-using-Jque

python function with Django

Hey guys I have a problem,
I have next function in my views.py:
#userRegistered
def getSyncGit(request, section):
print 'POTATOE' #(<-debug print)
cmd = '. script.sh 1'
p = sp.Popen(['/bin/bash', '-c', cmd], stdout=sp.PIPE, stderr=sp.PIPE)
result = p.wait()
return HttpResponseRedirect(getURL(request.LANGUAGE_CODE, '/assistant/configuration/project/list/'))
At the urls.py:
from .views import getSyncGit
url(r'^/project/sync/$', getSyncGit, {'section':'configuracion'}, name='pgetSyncGit'),
And in my template:
<script type="text/javascript">
function sendSyncProject()
{
$.ajax({url: "{% url 'pgetSyncGit' %}", success: function(result){
alert('cool');
}});
}
</script>
<td>
<input id="butSendSyncProject" type="button" name="butSendSyncProject" style="margin-left:1px;" value="{% trans 'Sinc' %}" onclick="sendSyncProject()" />
</td>
<td>
asdasdasdasdasddas
</td>
When I call to action with button, I can see thealert message, but the getSyncGit function is not executed.
When I call to action with url href, it redirects me to the url "/project/sync/", but the function neither executes....
Try to change your script to a script that writes a line into a file like "echo 'test' > tmp.txt" and tell us if tmp.txt is being created or not
Thank you for your answer #Oliver
I've tried what you've said and it doesn't work.
I've tried the following:
At the urls.py:
from .views import editDeProject
url(r'^/project/edit/0', editDeProject, {'section':'configuracion'}, name='pgetSyncGit'),
And now i have next function in my views.py:
def editDeProject(request, id, section):
"""Page Edit of DB de_project"""
errorTable = ''
form = None
if id == 0:
getSyncGit(request,id,section)
else:
try:
table = DeProject.objects.get(codProject=id)
if request.method == 'POST':
Using this method it works, it prints POTATOE and it generates file.txt, however I'm forcing url.py to take id 0 as an input.
therefore I believe the problem is when the (r'^/project/sync/(?P.*)/' gets generated

Web text input save into database without form- Django Javascript

I have an sqlite3 database setup with django 1.6 where I want web users to be able to enter text and see it in 3 live tables (high, low and latest) all on the same page. The one page ideally should have text entry, voting, display of the three tables updated when new entries go in or are voted on, and a search if possible if all that gets sorted (personal project, not commercial). I am also on win7 64 if that matters...
Currently I have: a working database the three tables displaying in a web page without update and some web text input via js (and failing to save to the database in Django).
I shied away from forms at first, as they seem to want separate html pages for input. Asking an experienced django coder, he helped me out with some javascript for text entry on the page. He said I didn't need to do it via forms and POST, GET, as the text was just going in with the initial score of 0 and the current datetime.
My issue now is that I cannot get the entered text to save into the database without error.
Since I need to program this in 2-3 weeks and am new to django (and oblivious to javascript, though I've done some Processing with PHP), my questions are;
Am I missing something obvious with the text input save to database?
-and-
Is there a way to have all this using forms and GET, POST in one page
so I can avoid a lot of javascript (unless it is truly easier)?
I am going to start to try to build this with Forms at the moment, but hope for a bit of guidance on best practice from wiser heads.
Here's the code so far:
urls.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
url(r'^i/$', 'entries.views.index'),
url(r'^add/(.*)$', 'entries.views.add'),
)
Models.py
from django.db import models
import datetime
from django.utils import timezone
class Entry(models.Model):
text = models.CharField(max_length=15)
score = models.IntegerField(default=0)
pub_date = models.DateTimeField('date published')
def __unicode__(self):
return self.text
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
was_published_recently.admin_order_field = 'pub_date'
was_published_recently.boolean = True
was_published_recently.short_description = 'Published recently?'
index.html
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
</head>
<body>
<ul>
{% for entry in latest_entry_list %}
<li>{{ entry.text }} &nbsp{{ entry.score }}</li>
{% endfor %}
</ul>
<ul>
{% for entry in high_entry_list %}
<li>{{ entry.text }} &nbsp{{ entry.score }}</li>
{% endfor %}
</ul>
<ul>
{% for entry in low_entry_list %}
<li>{{ entry.text }} &nbsp{{ entry.score }}</li>
{% endfor %}
</ul>
<style type="text/css" media="screen">
div h2 span { color: #ff0000; }
div span { color: #00ff00; }
#box { width: 400px; height: 400px; }
#h { color: #ff0000; }
</style>
<h3 id="h">title</h3>
<p>message: {{ text }}</p>
<input type="text" name="word" value="" id="input"/>
<script type="text/javascript" src="{{STATIC_URL}}post.js"></script>
</body>
post.js
console.log("hi from js");
$(document).ready(function() {
$("#input").bind("keypress", function(e) {
//enter key pressed
if (e.keyCode == 13) {
var args = {};
var text = $("#input").val();
$.get("/add/" + text, args).done(function(data) {
console.log("message: " + data);
});
}
});
});
views.py
from django.shortcuts import render
from django.http import HttpResponse
from entries.models import Entry
from django.db import models
import datetime
from django.utils import timezone
def index(request):
context = {
'latest_entry_list': Entry.objects.order_by('-pub_date')[:10],
'high_entry_list': Entry.objects.order_by('-score')[:10],
'low_entry_list': Entry.objects.order_by('score')[:10],
}
return render(request, 'entries/index.html', context);
def add(request, thingtoadd):
#created_date = models.DateTimeField('date published', default=datetime.now)
#created_score = '0'
#created_text = 'test'
#e = Entry(text=created_text, score=created_score,pub_date=created_date)
#e.save()
return HttpResponse('done')
I am unsure of defining the fields for populating the Entry....does the above look right?
I can uncomment the e=Entry(etc...) without error,
but when I uncomment the e.save(), the error is:
GET http://127.0.0.1:8000/add/a 500 (INTERNAL SERVER ERROR) jquery.min.js:4
send jquery.min.js:4
n.extend.ajax jquery.min.js:4
n.(anonymous function) jquery.min.js:4
(anonymous function) post.js:15
n.event.dispatch jquery.min.js:3
r.handle
I will be getting on with trying to do this in forms, but wonder if there is some good advice as to if that is possible - I would ideally like to avoid js extras as I am very unfamiliar with it and it would be another level of unknowns at this point. Any input greatly appreciated...
Your mistake in view function add:
created_date = models.DateTimeField('date published', default=datetime.now)
It must be value assign:
created_date = datetime.now()
Not field definition.
In advance you could specify auto_now_add=True in your model: https://docs.djangoproject.com/en/dev/ref/models/fields/#datefield
In that case field will be filled automatically.
Additional:
It is error in urls.py
You should do some fixes:
urls.py:
url(r'^add/$', 'entries.views.add'),
post.js
$("#input").bind("keypress", function(e) {
//enter key pressed
if (e.keyCode == 13) {
var text = $("#input").val();
var args = {'text': text};
$.get("/add/", args).done(function(data) {
console.log("message: " + data);
});
}
});
views.py
def add(request):
created_date = default=datetime.now()
created_score = '0'
created_text = request.GET.get('text')
e = Entry(text=created_text, score=created_score,pub_date=created_date)
e.save()
return HttpResponse('done')
Update - Solution
The solution in addition to the changes below was to add 'from datetime import datetime' in views....

Categories