Flask: Bad Request POST 400 - python

I use flask and firebase. I have 2 button in satis.html . When user press button2 , i want to retrieve some data from database and show it. But i get " Bad Request " Error.
Heres my code :
#app.route('/satis', methods=['GET', 'POST'])
def satis():
if (request.method == 'POST'):
sehir=request.form['il']
yas=request.form['yas']
id=request.form['id']
gun=request.form['satisgunu']
cins=request.form['cinsiyet']
tarz=request.form['satistarzi']
db = firebase.database()
db.child("names").push({"sehir": sehir,"yas":yas,"id":id,"gun":gun,"cins":cins,"tarz":tarz})
todo = db.child("names").get()
to = todo.val()
if request.form['submit'] == 'add':
db = firebase.database()
users_by_score = db.child("names").order_by_child("id").equal_to("2").get()
us = users_by_score.val()
return render_template('satis.html', t=to.values(),u=us.values())
return render_template('satis.html', t=to.values())

You have only handled for post method. You need to also handle the GET method situation.
#app.route('/satis', methods=['GET', 'POST'])
def satis():
db = firebase.database()
todo = db.child("names").get()
to = todo.val()
if (request.method == 'POST'):
sehir=request.form['il']
yas=request.form['yas']
id=request.form['id']
gun=request.form['satisgunu']
cins=request.form['cinsiyet']
tarz=request.form['satistarzi']
db.child("names").push({"sehir": sehir,"yas":yas,"id":id,"gun":gun,"cins":cins,"tarz":tarz})
if request.form['submit'] == 'add':
db = firebase.database()
users_by_score = db.child("names").order_by_child("id").equal_to("2").get()
us = users_by_score.val()
return render_template('satis.html', t=to.values(),u=us.values())
return render_template('satis.html', t=to.values())

Related

Python Flask Form not working anymore, any ideas why?

The app has worked before, but it has been a while. It requests data from the user that gets sent to a machine learning model. The page should be the same with the results posted at the bottom of html page.
app = Flask(__name__, template_folder='templates')
with open(f'model/model.pkl', 'rb') as file:
model = pickle.load(file)
#app.route('/', methods=['GET', 'POST'])
def main():
if request.method == 'GET':
return(render_template('index.html'))
if request.method == 'POST':
input_list = request.form.to_dict()
input_list = list(input_list.values())
input_list = list(map(int, input_list))
result = Predictor(input_list)
if int(result)==1:
prediction='High'
else:
prediction='Low'
return render_template("index.html",prediction_text = 'Thank you for submitting your details. Your credit risk is : {}'.format(prediction))
def Predictor(input_list):
to_predict = np.array(input_list).reshape(1,15)
result = model.predict(to_predict)
return result[0]
I've tried making two templates of the same html form, where one holds the submit button and the other displays the result.

Create a relationship between two db records in a form in Python / Flask / SQLAlchemy

I am desperately trying to do the following:
Capture details of 2 individuals in a Flaskform (i.e. a father and a mother). Each individual is an instance of an Individual class / model and stored in an SQLAlchemy table
When the second individual is added (could be the father or the mother), then a relationship is created with the ids of the two Individuals, in a Parents table. This creates a relationship record between the father and the mother. I'm happy that's all set up OK.
Main app code is below. I want to make sure I can grab both id's at the same time, to create the relationship (hence the print statements).
Yet the first time I add an individual, two print statements output:
New father ID is 1
New mother ID is None # this is probably expected as I haven't added the second Individual yet
Second time I add an individual, I get:
New father ID is None
New mother ID is 2 # What has happened to the first Individual's ID?
I have tried declaring global variables to write the ids back to but get errors about using a variable before they are declared.
Can anyone help?
from genealogy import app
from flask import render_template, session, redirect, url_for, request
from genealogy import db
from genealogy.models import Individual, Parents
from genealogy.individual.forms import AddIndividual
#app.route("/", methods=["GET", "POST"])
def index():
form = AddIndividual()
def fullname(first, last):
return first + " " + last
if request.method == "POST":
new_father = Individual("",None,None)
new_mother = Individual("",None,None)
new_child = Individual("",None,None)
new_partners = Parents(None,None)
if request.form.get("addfather") == "Add":
father_forenames = form.father_forenames.data
father_surname = form.father_surname.data
father_fullname = fullname(father_forenames, father_surname)
new_father = Individual(father_surname, father_fullname, father_forenames)
db.session.add(new_father)
session["new_father.id"] = new_father.id
db.session.commit()
# db.session.flush()
# if Parents.query.filter_by(father_id=new_father.id, mother_id=new_mother.id):
# pass
# else:
# new_partners = Parents(new_father.id, new_mother.id)
# db.session.add(new_partners)
# db.session.commit()
if request.form.get("addmother") == "Add":
mother_forenames = form.mother_forenames.data
mother_surname = form.mother_surname.data
mother_fullname = fullname(mother_forenames, mother_surname)
new_mother = Individual(mother_surname, mother_fullname, mother_forenames)
db.session.add(new_mother)
session["new_mother.id"] = new_mother.id
db.session.commit()
# db.session.flush()
# if Parents.query.filter_by(father_id=focus_father.id, mother_id=focus_mother.id):
# pass
# else:
# new_partners = Parents(focus_father.id, focus_mother.id)
# db.session.add(new_partners)
# db.session.commit()
if request.form.get("addchild") == "Add":
child_forenames = form.child_forenames.data
child_surname = form.child_surname.data
child_fullname = fullname(child_forenames, child_surname)
new_child = Individual(child_surname, child_fullname, child_forenames)
db.session.add(new_child)
focus_person = new_child
db.session.commit()
print("New father ID is " + str(session["new_father.id"]))
print("New mother ID is " + str(session["new_mother.id"]))
return render_template("home.html", form=form)
# return render_template("home.html", form=form, focus_father=focus_father, focus_mother=focus_mother,
# focus_person=focus_person, focus_partners=focus_partners)
return render_template("home.html", form=form)
if __name__ == "__main__":
app.run(debug=True)
Thanks to #van, here's the working code:
from genealogy import app
from flask import render_template, session, redirect, url_for, request
from genealogy import db
from genealogy.models import Individual, Parents
from genealogy.individual.forms import AddIndividual
#app.route("/", methods=["GET", "POST"])
def index():
form = AddIndividual()
def fullname(first, last):
return first + " " + last
if request.method == "POST":
new_father = Individual("",None,None)
new_mother = Individual("",None,None)
new_child = Individual("",None,None)
new_partners = Parents(None,None)
if request.form.get("addfather") == "Add":
father_forenames = form.father_forenames.data
father_surname = form.father_surname.data
father_fullname = fullname(father_forenames, father_surname)
new_father = Individual(father_surname, father_fullname, father_forenames)
db.session.add(new_father)
db.session.commit()
db.session.flush()
session["new_father.id"] = new_father.id
if request.form.get("addmother") == "Add":
mother_forenames = form.mother_forenames.data
mother_surname = form.mother_surname.data
mother_fullname = fullname(mother_forenames, mother_surname)
new_mother = Individual(mother_surname, mother_fullname, mother_forenames)
db.session.add(new_mother)
db.session.commit()
db.session.flush()
session["new_mother.id"] = new_mother.id
if request.form.get("addchild") == "Add":
child_forenames = form.child_forenames.data
child_surname = form.child_surname.data
child_fullname = fullname(child_forenames, child_surname)
new_child = Individual(child_surname, child_fullname, child_forenames)
db.session.add(new_child)
focus_person = new_child
db.session.commit()
print("New father ID is " + str(session["new_father.id"]))
print("New mother ID is " + str(session["new_mother.id"]))
return render_template("home.html", form=form)
# return render_template("home.html", form=form, focus_father=focus_father, focus_mother=focus_mother,
# focus_person=focus_person, focus_partners=focus_partners)
return render_template("home.html", form=form)
if __name__ == "__main__":
app.run(debug=True)

Pyodbc Error 07002 - Count field incorrect or syntax error - Insert Data From Form

I've been building a webapp for the HR department which will (hopefully) include the ability for staff to submit timesheets and I have become stuck when trying to submit a timesheet. The connection string is working as I can see other data from the database. I have been working through errors but this 07002 error is one I can't work out what is causing it.
I've tried two different ways to get this working. Here is the first attempt in my app.py file -
#app.route('/timesheet', methods=['GET', 'POST'])
def employee_timesheet():
if request.method == "POST":
employee_id = request.form['employee_id']
department = request.form['department']
mondaystart = request.form['mondaystart']
mondayend = request.form['mondayend']
tuesdaystart = request.form['tuesdaystart']
tuesdayend = request.form['tuesdayend']
wednesdaystart = request.form['wednesdaystart']
wednesdayend = request.form['wednesdayend']
thursdaystart = request.form['thursdaystart']
thursdayend = request.form['thursdayend']
fridaystart = request.form['fridaystart']
fridayend = request.form['fridayend']
saturdaystart = request.form['saturdaystart']
saturdayend = request.form['saturdayend']
result = request.form
cursor = cnxn.cursor()
cursor.execute('''INSERT INTO dbo.submitted_timesheet (employee_id, department, mondaystart, mondayend, tuesdaystart, tuesdayend, wednesdaystart, wednesdayend, thursdaystart, thursdayend, fridaystart, fridayend, saturdaystart, saturdayend,) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)''')
cnxn.commit()
flash("Your form was successfully submitted")
print("Form data submitted")
return redirect (url_for('success.html', result=result))
return render_template("staff_timesheets.html")
The other way then is -
#app.route('/timesheet', methods=['GET', 'POST'])
def employee_timesheet():
if request.method == "POST":
employee_id = request.form['employee_id']
department = request.form['department']
mondaystart = request.form['mondaystart']
mondayend = request.form['mondayend']
tuesdaystart = request.form['tuesdaystart']
tuesdayend = request.form['tuesdayend']
wednesdaystart = request.form['wednesdaystart']
wednesdayend = request.form['wednesdayend']
thursdaystart = request.form['thursdaystart']
thursdayend = request.form['thursdayend']
fridaystart = request.form['fridaystart']
fridayend = request.form['fridayend']
saturdaystart = request.form['saturdaystart']
saturdayend = request.form['saturdayend']
insert_query = '''INSERT INTO submitted_timesheet (employee_id, department, mondaystart, mondayend, tuesdaystart, tuesdayend, wednesdaystart, wednesdayend, thursdaystart, thursdayend, fridaystart, fridayend, saturdaystart, saturdayend,) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)'''
result = request.form
cursor = cnxn.cursor()
cursor.execute(insert_query, values)
cnxn.commit()
flash("Your form was successfully submitted")
print("Form data submitted")
return redirect (url_for('success.html', result=result))
return render_template("staff_timesheets.html")
If I submit a timesheet, I get the Pyodbc error in the title. Everything matches up in terms of column names and types. The HTML form should be fine too but can post it if needed for context.
Any ideas where I am going wrong?
Thank you!

How do I make independent API's?

I'm far from being an expert on the topic and my question might even make no sense, but I'm trying to make an app that gathers data from a server I made. There's a Python script I made that logs into a website and scrapes data from it. When you make a GET request to the API, the Python functions get called and the data is put on a server for the app to take. Thing is: whenever a user makes a GET request (or even a POST request, to send the credentials needed for the Python script to log in), the server changes for every user. For example, if a user posts his credentials, the dictionary "credentials" is changed for everyone and if a second user posts his credentials at the same time, the dictionary might get the wrong values for one of the two users. Here's the code:
from flask import Flask, request, jsonify
import backend as b
app = Flask(__name__)
credentials = dict()
subjectNames = ['Italiano', 'Inglese', 'Filosofia', 'Storia', 'Matematica', 'Informatica', 'Fisica', 'Scienze', 'Arte', 'Educazione Fisica']
#app.route('/login', methods=['POST'])
def getCredentials():
if request.method == 'POST':
username = request.get_json(force=True).get('username')
password = request.get_json(force=True).get('password')
credentials['username'] = username
credentials['password'] = password
return jsonify({'credentials': credentials})
#app.route ('/creds', methods=['GET'])
def creds():
return jsonify({'credentials': credentials})
#app.route('/api', methods=['GET'])
def api():
if request.method == 'GET':
query = str(request.args['query'])
if query == 'marks':
d = {}
m = b.getFullMarks(b.login(credentials['username'], credentials['password']))
for i in range(len(subjectNames)):
d[subjectNames[i]] = m[i]
return jsonify(d)
elif query == 'names':
d = {}
m = b.getNames(b.login(credentials['username'], credentials['password']))
for i in range(len(subjectNames)):
d[subjectNames[i]] = m[i]
return jsonify(d)
elif query == 'calendar':
d = {}
m = b.calendar(b.login(credentials['username'], credentials['password']))
d['Calendar'] = m
return jsonify(d)
elif query == 'badge':
d = {}
m = b.badge(b.login(credentials['username'], credentials['password']))
d['Badge'] = m
return jsonify(d)
if __name__ == '__main__':
app.run()
Leaving aside the fact that you keep all of the credentials in memory, and if the server crashes, you lost everything.
You can't use a dictionary to do as you want, as you already know, a dictionary can only hold a single representation of the same key (in our case, 'username'). so when a 2nd user calls the /login endpoint, you're overwriting the previous one and vice versa.
As mentioned before, most applications will generate a token on a successful login, and will send it back to the calling user.
The user will add it as a header on his upcoming requests, this allows the service to identify the calling user, and do whatever it needs.
You can look for existing implementations, or do something on your own.
but eventually, you'll need to map the token to the user, e.g:
#app.route('/login', methods=['POST'])
def getCredentials():
if request.method == 'POST':
username = request.get_json(force=True).get('username')
password = request.get_json(force=True).get('password')
token = generate_token_for_user(username, password)
credentials[token] = {'username': username, 'password': password}
return jsonify({'token': token})
and in the api call:
#app.route('/api', methods=['GET'])
def api():
token = request.headers['Authorization'] # assuming you're using this for your token
creds = credentials.get(token)
d = {}
if request.method == 'GET':
query = str(request.args['query'])
if query == 'marks':
m = b.getFullMarks(b.login(creds['username'], creds['password']))
for i in range(len(subjectNames)):
d[subjectNames[i]] = m[i]
return jsonify(d)
elif query == 'names':
m = b.getNames(b.login(creds['username'], creds['password']))
for i in range(len(subjectNames)):
d[subjectNames[i]] = m[i]
return jsonify(d)
elif query == 'calendar':
m = b.calendar(b.login(creds['username'], creds['password']))
d['Calendar'] = m
return jsonify(d)
elif query == 'badge':
m = b.badge(b.login(creds['username'], creds['password']))
d['Badge'] = m
return jsonify(d)
Offcourse, that maintaining a token lifecycle is a bit more complex, need to invalidate the token after a period of time, and you'll need to validate it on every request (usually with a middleware), but this is the concept.

Flask WTForms dynamic select field validation value is empty on POST

I am having trouble validating a dynamically generated WTForms SelectField. Somehow my self.choices is empty during POST while they are populated on the first GET request. Am I missing something?
app.py:
#app.route('/users/edit/<email>/', methods=['GET', 'POST'])
def users_edit(email):
match = False
for user in session['users']['message']:
if user['email']['S'] == email:
match = True
if match:
form = EditUserForm()
if request.method == 'GET':
form_data = session.get('edit_user_form_data', None)
if form_data:
form = EditUserForm(MultiDict(form_data))
form.shops_allowed.choices = [(str(shop['shop_id']['S']), str(shop['general']['M']['shop_name']['S'])) for i, shop in enumerate(session['shops']['message'])]
print(f"SHOPS_ALLOWED CHOICES WITH FORM DATA: {form.shops_allowed.choices}")
form.validate()
session.pop('edit_user_form_data', None)
else:
form.email.data = email
form.shops_allowed.choices = [(str(shop['shop_id']['S']), str(shop['general']['M']['shop_name']['S'])) for i, shop in enumerate(session['shops']['message'])]
print(f"SHOPS_ALLOWED CHOICES WITHOUT FORM DATA: {form.shops_allowed.choices}")
matched_shop = []
for user in session['users']['message']:
if user['email']['S'] == email and 'shops_allowed' in user.keys():
matched_shop = [allow['S'] for allow, shop in zip(user['shops_allowed']['L'], session['shops']['message'])]
form.shops_allowed.data = matched_shop
form.validate()
if request.method == 'POST' and form.validate_on_submit():
app.logger.info(f"PRE POST EDIT USER FORM DATA: {form.data}")
url = ...
<REDACTED POST REQUESTS ENDPOINT>
app.logger.info(f"POST EDIT USER RESPONSE: ({post_response.status_code}) {response_data}")
if post_response.status_code == 200:
session.pop('edit_user_form_data', None)
return redirect(url_for('users'))
else:
app.logger.info(f"EDIT USER FORM DATA: {form.data}")
session['edit_user_form_data'] = form.data
return redirect(url_for('users_edit', email=email))
elif request.method == 'POST' and form.validate_on_submit() == False:
app.logger.info(f"EDIT USER FORM DATA VALIDATION FAILED: {form.data}")
session['edit_user_form_data'] = form.data
return redirect(url_for('users_edit', email=email))
forms.py
class NonValidatingSelectMultipleField(SelectMultipleField):
def __len__(self):
return 1
def pre_validate(self, form):
pass
# HACK TO VALID A CHOICE FOR SELECT MULTIPLE
if self.data:
print(f"SELF DATA: {self.data}")
print(f"VALUES: {self.choices}")
values = list(self.coerce(c[0]) for c in self.choices)
print(f"PROCESSED VALUES: {values}")
for d in self.data:
if d not in values:
raise ValueError(self.gettext("'%(value)s' is not a valid choice for this multiple select field") % dict(value=d))
class EditUserForm(FlaskForm):
email = StringField('Email', [
validators.DataRequired(),
validators.Length(min=6),
validators.Email(message='Not a valid email address.')]
)
shops_allowed = NonValidatingSelectMultipleField(
'Shops',
widget = widgets.ListWidget(prefix_label=False),
option_widget = widgets.CheckboxInput(),
coerce=str
)
This renders the following logging:
SHOPS_ALLOWED CHOICES WITHOUT FORM DATA: [('decb5a00-fe45-484f-b887-b9bd41c4f0f2', 'My shop'), ('2cea2efa-7ccf-4bca-896d-16119d5fb7a8', 'My other shop')]
SELF DATA: ['decb5a00-fe45-484f-b887-b9bd41c4f0f2', '2cea2efa-7ccf-4bca-896d-16119d5fb7a8']
VALUES: [('decb5a00-fe45-484f-b887-b9bd41c4f0f2', 'My shop'), ('2cea2efa-7ccf-4bca-896d-16119d5fb7a8', 'My other shop')]
PROCESSED VALUES: ['decb5a00-fe45-484f-b887-b9bd41c4f0f2', '2cea2efa-7ccf-4bca-896d-16119d5fb7a8']
127.0.0.1 - - [03/Apr/2020 14:30:11] "GET /users/edit/my#email.com/ HTTP/1.1" 200 -
After POST:
SELF DATA: ['decb5a00-fe45-484f-b887-b9bd41c4f0f2', '2cea2efa-7ccf-4bca-896d-16119d5fb7a8']
VALUES: None
And on screen:
forms.py", line 35, in pre_validate values = list(self.coerce(c[0]) for c in self.choices) TypeError: 'NoneType' object is not iterable
Meh, after going over my code once more I finally found the issue. I am calling form.validate_on_submit() at the same time I am verifying if request.method == 'POST' which never gives me the possibility to populated the choices during POST.
Changed my code to be:
if request.method == 'POST':
form.shops_allowed.choices = [(str(shop['shop_id']['S']), str(shop['general']['M']['shop_name']['S'])) for i, shop in enumerate(session['shops']['message'])]
form.validate_on_submit()
And it started to work. Sometimes you just need to write things down to see the answer :-)

Categories