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:
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.
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.
Related
I'm pretty new to django and have been experimenting with some of the code
I want to build a form that starts with a parent record, lists the children of that record, and then when I click on a child (or a button in the row of that child) shows the children under that in a datatableview object. phew It should look a little like this:
So the dataset is the primary object into the view, and the tables are a datatables filtered by the dataset id, which all works fine... but how do I get the {{ datatable }} to render in context?
The current view code is pretty basic - this is initially all just for display.
def datasetview(request, datasetid):
dataset = get_object_or_404(DataSet, pk=datasetid)
context = {
'dataset': dataset,
}
return render(request, 'data/dataset_view.html', context)
within the html template, I render the table list with:
{% for datatable in dataset.datatables.all %}
{% if not datatable.deleted %}
<tr>
<td class="p-1 align-middle">{{ datatable.tablename }}</td>
<td class="p-1 align-middle"><button type="button" class="btn btn-outline-primary" onclick="fill_attribute_table({{ datatable.datatableid }})">Edit</button></td>
</tr>
{% endif %}
{% endfor %}
I've been able to render the dataviewtable as a generic page using the demo code provided at pypi.org/project/django-datatable-view (that's how I produced the hacky screen image above) but have no idea how to blend the results here together or pass the datatableid that I can easily attach to the row of tables (the edit button currently throws up an alert with the relevant id...
Hi there I have to use one unique HTML page to display a few fields that will be populated with some data retrieved from a csv file.
I want to use the WTF quick form to pass all the fields together to the HTML page, since I won't know the field names, because they can be retrieved from different csv files(they will be equivalent to the column header of the csv).
The only problem is that I want them to be displayed in two columns (div), so half fields in one colums, half in the other, while quick form will show them in a single vertical list.
How can I sort this out in the easiest way? any attribute to add to the quick form for the layout?
I have tried the following using wtf.form_field, but in this way I must know the name of each field, and I will have to create one HTML page for each CSV file, while I want to have 1 HTML page with quick form, but I can't have the fields displayed in two columns that way.
<div class="row">
<div class="col-md-6">
{{ wtf.form_field(form.COD_SPORTELLO) }}
{{ wtf.form_field(form.QU_CAP) }}
{{ wtf.form_field(form.QU_CAP_INTER) }}
{{ wtf.form_field(form.CAUSALE) }}
{{ wtf.form_field(form.ONERI_RATE_VAL) }}
{{ wtf.form_field(form.FLAG_ANTIRIC) }}
{{ wtf.form_field(form.FLAG_VIG) }}
</div>
<div class="col-md-6">
{{ wtf.form_field(form.COD_RAPPORTO) }}
{{ wtf.form_field(form.QU_CAP_VALUTA) }}
{{ wtf.form_field(form.DATA_SCADENZA) }}
{{ wtf.form_field(form.ONERI_RATE) }}
{{ wtf.form_field(form.QU_INTER_VALUTA) }}
{{ wtf.form_field(form.FLAG_AR) }}
</div>
</div>
I think it's a bit tricky because even if I pass some parameter to the quick form like horizontal_columns for instance ( Must be a 3-tuple of column-type, left-column-size, right-column-size), it will create a second column, but it will display the fields only one column still, so somehow I have to tell him that I want half of the fields on one column and half on the other column (div).
I can't use form_field and list each fileld name cause I won't know the field names.
The fields can be assigned a class directly from the template. If you know what bootstrap classes you need then you call it with the field with a keyword argument class
As explained in this answer
Add a css class to a field in wtform
I am new to SQLAlchemy and HTML forms and need to understand how to delete multiple rows in my dB table that correspond to are checked checkboxes in my HTML form. As it stands only the first checked item is being deleted from the table. I was hoping this could be done without a for loop on the SQLAlchemy side?
Here is my HTML code:-
<ul>
{% for alert in alerts %}
<li> <input name="alert_id" type="checkbox" value="{{ alert.alert_id }}"/> Ticker:{{ alert.ticker }} Price:{{ alert.price }}</li>
{% endfor %}
</ul>
And the flask python SQLAlchemy script:-
if request.method == "POST":
if request.form["alert_id"]:
Alert.query.filter(Alert.alert_id == request.form["alert_id"]).delete()
db.session.commit()
This line
Alert.query.filter(Alert.alert_id == request.form["alert_id"]).delete()
should be
Alert.query.filter(Alert.alert_id.in_(request.form["alert_id"])).delete()
which does a SELECT * FROM <table_name> WHERE alert_id IN (<val>, <val2>)
Also, it's good to stick to request.form.getlist("alert_id") instead of request.form["alert_id"] so you can always make sure you get a list and not a KeyError in case alert_id doesn't exist.
I am trying to make a web app like a mini-tweets. The posts are pulled out from a database and I want to have an 'up vote' button for each post, like the following picture.
Each post has an id, author, body, and likes property. When an up vote is clicked, the likes property needs to be updated.
My question is how to determine which button is clicked. What would be a good strategy in this case for the route() function and the html template?
I was thinking of adding a name to each button and put post.id in the name, then check if request has it. But the number of posts are not known before hand, how should I write the request check in route() function?
My current template is as follows
<table class="table table-striped">
{% for post in posts %}
<tr>
<td> {{ post.id }} </td>
<td> <img src="{{ post.author.avatar(50) }}"> </td>
<td> <b>{{ post.body }}</b> </td>
<td> <button type="button" name='{{'up.'+ post.id|string}}' class="btn btn-default">
<span class="glyphicon glyphicon-thumbs-up" aria-hidden="true"></span>
</button>
{{ post.likes}} </td>
</tr>
{% endfor %}
</table>
and the current route() is like this
#bbs.route('/', methods=['GET', 'POST'])
def index():
posts = Post.query.all()
return render_template('bbs/index.html', posts=posts)
A clean way to do that would be to add a data attribute, in your button tag and do one ajax request per upvote / downvote.
https://developer.mozilla.org/en/docs/Web/Guide/HTML/Using_data_attributes
In your case, it would be called data-id.
Then in your javascript, when the button is clicked, get this data attribute value, and craft your url as such :
/upvote/<data-id>
And call it using an ajax GET request (so the page doesn't refresh).
Now on flask side get the id as such :
#app.route('/upvote/<post_id>')
def upvote(post_id):
print('%s upvoted' % post_id)
# do your db update here and return a json encoded object
And on javascript side again, when you get your answer from flask, update your button accordingly.
Assuming you put another class in your upvote button for instance : upvote_button and you use jQuery, your javascript could look like that :
<script type='text/javascript'>
$('.upvote_button').click(function(ev){
var id = $(ev.currentTarget).attr('data-id');
$.get( "/upvote/" + id, function( data ) {
// change your button here, and remove its upvote_button class
alert(data);
});
});
</script>
I would like to click on a link from my Django page and based on the link i clicked display a new database query filter from that name on the list
<tr>
<th>RootGroup List</th>
</tr>
{% for status in root %}
<tr>
<td><a href={{status.rootgroup }}> {{ status.rootgroup }} </a></td>
#I WANT TO CLICK THE LINK AND DISPLAY A NEW DATABASE BASED ON THE NAME WITH A FILTER OF THE NAME
</tr>
{% endfor %}
def display(request):
x = re.search('d.*','% url ''detail'' poll.id %')
rootFilter = Viewroot.objects.filter(rootstatus__gt=0, type = 1, ("LINK NAME")).values('rootgroup').distinct() #RootGroup List
#return render_to_response('status/index.html', { 'root' : rootFilter },context_instance=RequestContext(request))
#return HttpResponse( x.group(0)),render_to_response('status/index.html', {'app' : appFilter})
return HttpResponse("You displayed ", j )`
Basically, you can make this work by using named groups in your urls.py patterns, e.g.:
(r'^links/(?P<value>\w+)/$', display)
Then, you can access saved part of url inside your view, like:
def display(request, value=None):
print value
And, of course, you should use appropriate url in the template:
<td> {{ status.rootgroup }} </td>
Also see documentation.