Reputation: 1380
I've created a HTML table that lists many rows from a SQLAlchemy table. The table is created with a loop using jinja2 templates:
{% for single_merchant in merchants %}
<tr>
<td>{{single_merchant.id}}</td>
<td><button type="button" class="btn btn-sm btn-outline-danger">Delete</button>
</tr>
Each of the rows has a "delete" button. Im am trying to figure out how can I assign the delete button to delete that particular SQLalchemy row. I tried creating the button as a separate flask form called delete_form
and adding an id="{{single_merchant.id}}
attribute to the button
like so:
{% for single_merchant in merchants %}
<tr>
<td>{{single_merchant.id}}</td>
<form method="post">
{{ delete_form.hidden_tag() }}
<td>{{ delete_form.delete(id=single_merchant.id) }}</td>
</form>
</tr>
In the app.py I then created an if statement:
if delete_form.validate_on_submit():
print(f"merchant to delete ID - {delete_form.delete.id}")
I was hoping to get the single_merchant.id
in the output and use it in the if statement to delete the particular merchant from my SQLAlchemy table, but instead I got in the output merchant to delete ID - delete
even though from the HTML file the id
attribute had a value of 1 since {{single_merchant.id}}
is 1
Is there a way how to execute SQLAlchemy row deletion from HTML tables? Here's a rough example how the HTML table is expected to look like:
Upvotes: 2
Views: 2979
Reputation: 101
You can use your original approach as well just add a hidden field to the form that has your delete button in which the value could be your id. You just have to then explicitly define the csrf_token
rather than using the hidden_tag()
method.
In your WtfForm class object define a hidden field like:
class DeleteForm(FlaskForm):
delete_id = HiddenField("Hidden table row ID")
delete = SubmitField("Delete")
Render it in your HTML Jinja2 template like this. Notice I flipped the <td>
and the <form>
so that your whole table data cell is the form
{% for single_merchant in merchants %}
<tr>
<td>{{single_merchant.id}}</td>
<td>
<form method="post">
{{ delete_form.csrf_token }}
{{ delete_form.delete_id(value=single_merchant.id) }}
{{ delete_form.delete(class="btn btn-danger") }}
</form>
</td>
</tr>
Then in your code you can easily check it using the wtfform validate_on_submit()
and then use the SQLAlchemy get()
method to query for that id pulling the value from the hidden fields data
attribute.
def post(self):
if self.delete_form.validate_on_submit():
entry_to_delete = YourSQLAlchemyTableClassObject.query.get(self.delete_form.delete_id.data)
db.session.delete(entry_to_delete)
db.session.commit()
You could if you wanted to combine the entry_to_delete
line with the db.session.delete()
by just putting the query to your table using the hidden field data property into the call to the delete()
method. I like to separate those pieces in case I need to do anything additional to the found entry before I delete it but it doesn't matter.
Here is a screenshot of one of my apps I built for my family that allows my kids to add suggestions for our Disney Vacations. I didn't use a cool trash can icon like you did but you get the point.
Upvotes: 0
Reputation: 1426
Implement a route to handle the deletion:
def merch_delete(mid):
merch = Merchant.query.filter_by(id=mid).first()
if merch:
msg_text = 'Merchant %s successfully removed' % str(merch)
cs.delete(merch)
cs.commit()
flash(msg_text)
return redirect(url_for('merchants_view'))
Then, add the following to a column in your jinja table:
<a href="{{ url_for('merch_delete', mid=single_merchant.id) }}"
onclick="return confirm('Do you want to permanently delete merchant {{ merchant }}?');" title="Delete Merchant">
<i class="material-icons" style="font-size:16px">delete</i></a>
The icon and Js verification step are optional.
Upvotes: 5