Using Flask to send form data to a database - python

I've created a simple web page with a text field and a button. I want my application to update a record in my database with the content of the text field when I click the button. Seems simple enough, but I can't figure out what I'm missing. Here's my code thus far:
app.py sample
#app.route('/update-audit/', methods=['POST'])
def update_audit(test_name, description):
cur = connect_db()
cur.execute('UPDATE audit SET description = ? WHERE test_name = ?', (description, test_name,))
return render_template('clicked.html')
audit.html sample
<form action="{{ url_for('update_audit') }}" method="post">
<td>{{ row[2] }}</td>
<td>
<input type="text" id="desc" value="{{ row[3] }}" size="140">
<input type="hidden" name="update_audit" value="{{ row[2] }}, desc"/>
<input type="submit" class="btn btn-success" value="Update"/>
</td>
</form>
clicked.html
<!DOCTYPE html>
{% extends "layout.html" %}
{% block content %}
<body>
{{ form.description }}<br />
</body>
{% endblock %}
table sample
id | tool name | test name | description
========================================
1 | "tool1" | "test1" | "update me!"
Not sure if I'm missing an essential concept (I played around with flask_wtf and didn't get anywhere) or if I'm a step or two away from making this happen.

Set a name attribute for text input so that it gets sent with the submitted form.
<input name="description" type="text" id="desc" value="{{ row[3] }}" size="140">
Update your view function to get description from the POST dictionary attribute of request. test_name also needs to be updated to an appropriate value.
#app.route('/update-audit/', methods=['POST'])
def update_audit():
description = request.form.get('description')
test_name = request.form.get('update_audit')
cur = connect_db()
with cur:
cur.execute(
'UPDATE audit SET description = ? '
'WHERE test_name = ?;', (description, test_name,))
# commit changes to the database
return render_template('clicked.html')

Figured it out:
app.py sample
#app.route('/update-audit/', methods=['POST'])
def update_audit():
description = request.form.get('description')
test_name = request.form.get('test_name')
sql = 'UPDATE audit SET description=? WHERE test_name=?'
conn = sqlite3.connect(DATABASE)
cur = conn.cursor()
cur.execute(sql, (description, test_name))
conn.commit()
conn.close()
return render_template('clicked.html', data=(test_name, description))
audit.html sample
<form action="{{ url_for('update_audit') }}" method="POST">
<td>
<input type="hidden" name="test_name" value="{{ row[2] }}">{{ row[2] }}</input>
</td>
<td>
<input type="text" name="description" id="desc" value="{{ row[3] }}" size="100" maxlength="140"/>
<input type="submit" class="btn btn-success" value="Update"/>
</td>
</form>
</tr>
The answer is a combination of the right SQL-Alchemy commands, and ensuring that I'm sending the data to the update_audit function via two input-tags in audit.html.

Your render_template should get a form argument:
return render_template('clicked.html', form=form)
It is also not clear in the code you provided where the Forms are treated in python and where the variable row comes from.

Related

I am haveing some issues with a post method, i am getting {"detail":"Method Not Allowed"}

I am new to developing in general and I am trying to figure out why i keep getting {"detail":"Method Not Allowed"} here is a snipit of what i have. I am printing the http variables on the site so I know i am getting correct values. in this case strategy.id == 1 and stock.id == 1 I have checked the sql statement by manually running it in a sql viewer as
INSERT INTO stock_strategy (stock_id, strategy_id) VALUES (1, 1)
and that works as well. I am sure i am just missing a comma or some other little thing, but i cannot for the life of me find it.
<form method="post">
<select name="strategy_id">
{% for strategy in strategys %}
<option value="{{ strategy.id }}">{{ strategy.name }}</option>
{% endfor %}
</select>
<input type="text" name="stock_id" value="{{ stock.id }}" />
<input type="submit" value="Apply strategy" />
</form>
#app.post("/apply_strategy")
def apply_strategy(strategy_id: int = Form(...), stock_id: int = Form(...)):
connection = sqlite3.connect(config.db_path)
cursor = connection.cursor()
cursor.execute("""
INSERT INTO stock_strategy (stock_id, strategy_id) VALUES (?, ?)
""", (stock_id, strategy_id))
connection.commit()
return RedirectResponse(url=f"/strategy/{strategy_id}", status_code=303)

Make custom form manually in Django based on a model

I am making a basic attendance record system with following models in my models.py file : Department, Employee, Absence.
Absence model is as below:
class Absences(models.Model):
emp_id = models.ForeignKey(Employees, on_delete=models.CASCADE, null=False)
leave_date = models.DateField(null=False)
leave_type = models.ForeignKey(LeaveTypes, on_delete=models.CASCADE)
absence_added = models.DateTimeField(auto_now_add=True)
absence_updated = models.DateTimeField(auto_now=True)
Now I want to create a form that lets you select date (that will be inserted in leave_date column) and a list of all employees with a dropdown (populated with leave_type) and submit button (which once clicked with save absences to database based on Absences model above.
How do I do this?
I found the solution.
You can make insertions directly into a model by simply instantiating an object of the model's class with values you want to insert into the model's table, and then run .save() method on that object.
I wanted to make a form that could make multiple entries in Absences model (the single entry form is easy to create using CreateView class). So I created a template that had the form containing the input fields depending on the number of employees(from Employees model) who's attendance needed to be marked. Following is the code of the template's form.
<form method="POST">
{% csrf_token %}
<label for="id_leave_date">Date</label>
<input type="date" name="leave_date" class="form-control" placeholder="Select a date" required="" id="id_leave_date">
<br>
<table class="table table-hover">
<thead>
<tr>
<th>Employee</th>
<th>Absence</th>
</tr>
</thead>
<tbody>
{% for emp in emps %}
<tr>
<td>{{ emp.emp_name }}</td>
<td>
<input type="radio" name="{{ emp.pk }}" id="p{{ emp.pk }}" value="present" checked> <label for="p{{ emp.pk }}">Present</label>
{% for leave in leaves %}
<input type="radio" name="{{ emp.pk }}" id="{{ leave.pk }}{{ emp.pk }}" value="{{ leave.pk }}"> <label for="{{ leave.pk }}{{ emp.pk }}">{{ leave.leave_type }}</label>
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<input type="submit" value="Mark Attendance" class="btn btn-primary">
</form>
To control the template, I created a view called mark_all_attendance(). This view showed the above mentioned template if it was accessed with a GET request and would send the template info it needed to generate form. If the view was accessed through POST request, it would process the submitted form in the template by manually accessing the key-value pairs of submitted form fields by iterating over all the pairs. On each iteration it instantiates objects of Absences class using submitted a form field set, and then running the .save() method on that object. This inserts the data in field set being iterated over into the Absences table. Then redirect the browser to a success page using HttpResponseRedirect. Following is the view code:
`def mark_all_attendance(request):
submitted = False
all_emps = models.Employees.objects.all()
leaves = models.LeaveTypes.objects.all()
if request.method == 'POST':
leave_date_from_post = datetime.datetime.strptime(request.POST['leave_date'], '%Y-%m-%d').date()
print('Original: ', request.POST['leave_date'])
print(leave_date_from_post)
for key, value in request.POST.items():
if not (key == 'csrfmiddlewaretoken' or key == 'leave_date'):
# print(key + " : " + value)
if value != 'present': #if present, don't insert record in absences table
record = models.Absences(
emp_id = models.Employees.objects.get(pk=key),
leave_type = models.LeaveTypes.objects.get(pk=value),
leave_date = leave_date_from_post
)
record.save()
return HttpResponseRedirect('/attendance/markallattendance?submitted=True')
else:
if 'submitted' in request.GET:
submitted = True
return render(request, 'attendance/markallattendance.html', {'emps': all_emps, 'leaves': leaves, 'submitted': submitted})`

HTML form button not deleting rows from sqlite database

I have built a forum in pythonanywhere using python and html, in which users can post information that gets inserted into a sqlite database. At the bottom of each post is a delete button that will delete the post that it's under from the database and refresh the page. Right now the delete button only refreshes the page while the post remains. I am wondering how to edit the code so that the post which the form button is attached to is deleted and the page is refreshed.
HTML Code snippet
{% for post in forumposts %}
<tr>
<td>
<h1>{{post[1]}}</h1>
<h3>{{post[3]}}</h3>
<p>{{post[2]}}</p>
<p>{{post[6]}}</p>
<img src="{{post[7]}}" alt="Wrong image link.">
<p></p>
<form action="{{ url_for('delete_post') }}" method=POST class=delete-post>
<input type=hidden value="{{ postid }}"name=post_to_delete></input>
<input type=submit></input>
</form>
</td>
</tr>
{%endfor%}
</table>
Python Code snippet
#app.route('/delete', methods=['POST'])
def delete_post():
db = connect_db()
db.execute('DELETE FROM posts WHERE postid = ?', [request.form['post_to_delete']])
db.commit()
db.close()
return redirect(url_for('forum'))
Got the code working.
HTML
{% for post in forumposts %}
<tr>
<td>
<h1>{{post[1]}}</h1>
<h3>{{post[3]}}</h3>
<p>{{post[2]}}</p>
<p>{{post[6]}}</p>
<img src="{{post[7]}}" alt="Wrong image link.">
<p></p>
<form action="{{ url_for('delete_post') }}" method=POST class=delete-post>
<input type=hidden value={{post[0]}} name=post_to_delete></input>
<input type=submit value=POST></input>
</form>
</td>
</tr>
{%endfor%}
</table>
PYTHON
#app.route('/delete', methods=['POST'])
def delete_post():
if request.method == 'POST':
db = connect_db()
db.execute('DELETE FROM posts WHERE postid = ?', (request.form['post_to_delete'],))
db.commit()
db.close()
return redirect(url_for('forum'))
Hope this helps someone. :)

Search function in Flask

I have a problem with my search. At the moment i am trying to write a small receipe portal and i am trying to search words in tables user,category and recipe. When i write some word, i receive an error message:
Bad request. The browser (or proxy) sent a request that this server
could not understand.
I suppose, that problem stays in my function search, but i dont see it.
#app.route("/search", methods=['GET', 'POST'])
def search():
cursor = g.con.cursor()
cursor.execute('SELECT * FROM nutzer, kategorien, rezepte WHERE Nutzername OR Titel = %s', (request.form["search"],))
result = cursor.fetchall()
cursor.close()
return render_template('Results.html', result = result)
{% extends "layout.html" %}
{% block body %}
<table border="1">
{% for i in result %}
<tr><td>{{ i.1 }}</td></tr>
{% endfor %}
</table>
{% endblock %}
HTML Code of the searchbar
<form action="search">
<input name="search" type="text" placeholder="suchen" value="{{ request.form.search}}" required />
<button>finden</button>
</form>
request.form() implies the POST method, while the default one is GET. You should either check request.method and use request.args() in the case of GET, or add the argument method="POST" to the <form> (and leave POST as the only accepted method in #app.route().
I think your form action has to point to your search endpoint.
<form action="{{ url_for(search) }}">
<input name="search" type="text" placeholder="suchen" value="" required />
<button>finden</button>
</form>

FLASK HTML field for Mysql query

Hello Stackoverflow community,
I am new to FLASK however while the learning curve has been very steep, there is one item that I have not been able to get my head around.
I am using a very simple HTML seach form, into which users type the name of a city, this input gets passed to a Mysql query and returns output into a Table.
Everything works except that I can't get the variable to pass into Mysql... if I fix the query it works.
I tried to work with FLASK WTForms, POST and GET requets, but I don't know where I am going wrong.
The variable data that I am passing is not confidencial, so I have no concern if it shows up in the URL.
Here just the simple FORM (I guess not correct)
<form>
<div class="form-group">
<div class="col-sm-3">
<input type="text" placeholder="City Name" name="City_Name" action=/search class="form-control">
</div>
<div class="form-group">
<div class="col-sm-2">
<input type="submit" value="SEARCH" class="btn btn-primary btn-block">
</div>
</div>
</form>
Here the table output (working perfectly)
<table class="table table-striped">
<tr>
<th>PO_Number</th>
<th>Plant Name</th>
<th>GMID</th>
<th>Material</th>
<th>INCOTERM</th>
<th>Vendor</th>
<th>Vendor Count</th>
</tr>
{% for row in tabledata %}
<tr>
<td>{{ row['PO_Number'] }}</td>
<td>{{ row['PN'] }}</td>
<td>{{ row['GD'] }}</td>
<td>{{ row['MN'] }}</td>
<td>{{ row['INCO'] }}</td>
<td>{{ row['VNGS'] }}</td>
<td>{{ row['CVNGS'] }}</td>
</tr>
{% endfor %}
</table>
Here the Python code
from flask import Flask, render_template, request, url_for
from dbhelper_single_search import DBHelper
app = Flask(__name__)
DB = DBHelper()
#app.route('/table')
def table():
try:
tabledata = DB.table_inputs()
except Exception as e:
print(e)
tabledata = None
return render_template("table.html", tabledata=tabledata)
if __name__ == '__main__':
app.run(port=5000, debug=True)
Data Base Helper Mysql (the valye for PLN should change based on the input in the Form.
import pymysql
class DBHelper:
def table_inputs(self):
connection = self.connect()
PLN="**City_Name**"
try:
query = "SELECT Plant_Geo, Plant_Code, Plant_Name, GMID, Material_Name, GROUP_CONCAT(DISTINCT Vendor_Name_GS ORDER BY Vendor_Name_GS) as VNGS, sum(2014_USD), sum(2015_USD), sum(2016_USD) FROM invoice_report WHERE plant_code like '%s' GROUP BY GMID ORDER BY sum(2015_USD) DESC" %(PLN);
with connection.cursor(pymysql.cursors.DictCursor) as cursor:
cursor.execute(query)
return cursor.fetchall()
finally:
connection.close()
Thank you in advance for any help.
I think you need to set the action on the <form> element, rather than <input> and you want to direct it to the same Flask endpoint (I assume?):
<form method="GET" action>
<div class="form-group">
<div class="col-sm-3">
<input type="text" placeholder="City Name" name="City_Name" class="form-control">
</div>
</div>
<div class="form-group">
<div class="col-sm-2">
<input type="submit" value="SEARCH" class="btn btn-primary btn-block">
</div>
</div>
</form>
Update your helper class a little to accept a city variable from your view function (you could tighten this up a bit more):
import pymysql
class DBHelper:
def table_inputs(self, city):
connection = self.connect()
PLN = "**%s**" % city
try:
query = "SELECT Plant_Geo, Plant_Code, Plant_Name, GMID, Material_Name, GROUP_CONCAT(DISTINCT Vendor_Name_GS ORDER BY Vendor_Name_GS) as VNGS, sum(2014_USD), sum(2015_USD), sum(2016_USD) FROM invoice_report WHERE plant_code like '%s' GROUP BY GMID ORDER BY sum(2015_USD) DESC";
with connection.cursor(pymysql.cursors.DictCursor) as cursor:
# actually better to pass parameters like this:
cursor.execute(query, (PLN,))
return cursor.fetchall()
except Exception as err:
# this may also help find errors generated above...
print(err)
finally:
connection.close()
Then, update your view function to test if city is submitted and submit it to your helper class:
#app.route('/table')
def table():
// the second argument is the default if "City_Name" is not submitted
city = request.args.get('City_Name', 'New York')
try:
tabledata = DB.table_inputs(city)
except Exception as e:
print(e)
tabledata = None
return render_template("table.html", tabledata=tabledata)

Categories