flask with many buttons and database update - python

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>

Related

Generate data when button/link is clicked Django

I'm very new to Django and web apps. I have an HTML page that allows users to search database for player names. An HTML table is returned. Each entry is a player's performance in relation to a game they played. Each game has 10 players associated with it
search_db.html
<h1>Search Results for: {{searched}}</h1>
<table>
{% for player in match %}
<tr>
<td>
<a href=search_player_db/{{player.match_id}}>{{player.match_id}}</a>
</td>
<td>{{ player.name}}</td>
<td>{{ player.role}}</td>
<td>{{ player.win_or_loss}}</td>
</tr>
{% endfor %}
</table>
{{IM TRYING TO GENERATE DATA HERE}}
The match id is a link that brings the user to a page with additional details related to the match
match_details.html
{%block stats%}
<body>
<h1>Winning team</h1>
{%for player in winners %}
<li>
{{player.name}}
{{player.role}}
</li>
{%endfor%}
<h1>Losing team</h1>
{%for player in losers %}
<li>
{{player.name}}
{{player.role}}
</li>
{%endfor%}
</body>
{%endblock%}
Instead of being redirected to a new page when clicking the link, I'd like to load the content from match_details.html into the page below the table on search_db.html through the button/link in search_db.html. That way the user can click through search results
views.py
def search_playerdb(request):
if request.method == "POST":
searched = request.POST['searched']
players = PlayerInfo.objects.filter(player_name__contains=searched)
context={
'searched': searched,
'players': players}
return render(request, 'searchdb.html', context)
else:
return render(request, 'searchdb.html', {})
def display_match(request, matchid):
match = PlayerInfo.objects.filter(match_id=matchid)
winners = match.filter(win_or_loss=True)
losers = match.filter(win_or_loss=False)
context = {
'match': match,
'winners': winners,
'losers': losers,}
return render(request, 'match_details.html', context)
In order to do this you'll need to use Javascript to make an AJAX call. In case you're unaware, an AJAX call allows a web page to send or receive data without having to refresh the page.
This can be done using pure javascript - Example https://www.w3schools.com/xml/ajax_intro.asp
Or you could use a library to abstract some of the complexity away. One example of this would be JQuery https://www.w3schools.com/jquery/ajax_ajax.asp
In either case, you will be calling a new URL on your site.

How to render multiple update forms in Django

here is my problem.
I have a list of objects that I display in a table and all works just fine except that I would like to edit them inside a modal and submit them using AJAX.
I though that it was a simple idea to render, for each row, a form with the inputs pre-filled and then submit the selected form with AJAX.
I wonder if there is a relatively simplified way to render the UpdateForm without writing manually all the input fields.
Something like this:
<table>
{% for transaction in transactions %}
<tr>
<td>{{ transaction.date|date:"d.m.Y" }}</td>
<td>{{ transaction.amount }}</td>
<td>
Edit
<div class="modal" id="edit{{ transaction.id }}">
{{ transaction_form }}
</div>
</td>
<tr>
{% endfor %}
</table>
But how can I pass the form from the view?
The way I'm currently doing it is that when the user click on edit the page refresh and the modal is displayed with the form prefilled but it is (a) slow to open and (b) I don't think it is a nice way to do it.
This is my current code
views.py
class ProjectDetailView(DetailView):
model = Project
template_name = "template.html"
context_object_name = "project"
def get_transactions(self):
transactions = Transaction.objects.filter(project=self.get_object())
return transactions
def get_transaction_form(self):
form = TransactionForm()
if self.request.POST:
form = TransactionForm(self.request.POST)
elif 'edit_entry' in self.request.GET:
form = TransactionForm(instance=self.get_entry())
return form
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['transactions'] = self.get_transactions()
context['transaction_form'] = self.get_transaction_form()
return context
template.html
<table>
{% for transaction in transactions %}
<tr>
<td>{{ transaction.date|date:"d.m.Y" }}</td>
<td>{{ transaction.amount }}</td>
<td>
Edit
</td>
<tr>
{% endfor %}
</table>
<div class="modal" id="edit-modal">
{{ transaction_form }}
</div>
<script>
{% if 'edit_entry' in request.GET %}
$('#edit-modal').modal('show')
{% endif %}
</script>
Thank you for any feedback
This solution needs you work with Javascript to do that,
when the user clicks 'Edit' for an object on your page,
you send AJAX request (using Fetch API or Jquery) to your view,
The view will return HTML of the form and you put this HTML in the modal's body
Show the modal with an action button to submit the form.
As the user clicks submit, your code submits the form through Ajax, you can use Formdata or AjaxForm for that, the view which return an JSON or HTML which indicates if the data is saved successfully or not.
The problem I'm not a Class-Based View guy so I can't give you specifics from Django side.

Pass value to new page in Flask when button is clicked

Basically I have a for loop to generate N buttons. Each button has a name and an id to recognize the activity. When one of these buttons is clicked, a new HTML page is opened in order to display the info of that activity. I could open the page but I need to pass the value of the button or I won't know which activity was clicked. There must be a pattern to do this.
You can check the code here:
<div class="activities">
<h2>Activities</h2>
{% set i = [0] %}
{% for d in data %}
<button class="btn btn-info" style="margin: 10px;" value="{{ indexs[i[0]] }}">{{ d }}</button>
{% if i.append(i.pop() + 1) %}{% endif %}
{% endfor %}
</div>
#views.route('/activity')
def activity():
return render_template("activity.html")
need to pass the value of the button
Simplest way I can think of is using URL query parameters, simplified example:
HTML snippet:
<div>
<button>first</button>
<button>second</button>
<button>third</button>
</div>
Flask:
from flask import request
...
#views.route('/activity')
def activity():
return "You clicked " + request.args["buttonid"] + "button"
must be a pattern to do this
FORMs (HTML tag <form>) are currently in use for this purpose.

How to add forms to a dictionary upon submission

I am creating a shopping cart as a part of the application I'm building.
I am trying to figure out how to add a form submission to a dictionary (I think this is what I need to do).
So for example this is what the page would look like(This is just test data).
Upon Clicking the add button I want the item name and price to populate in the Orders table to the right of the Pricing table(To start off). Once all orders have been added I'd click the Order button and that will order the added items in some type of list to the database using sqlalchemy. Now I feel strongly and I may be wrong that upon submitting form using add button that the form needs to be added to a dictionary. I just don't know how to save that dictionary and where that dictionary should be stored? Here is my code as of now.
routes.py
I tried putting the dictionary with in the route function but a single instance is created on each submission. So nothing is really being saved to dictionary.
#app.route('/equipment', methods=['POST', 'GET'])
def equipment():
form = OrderEquipmentForm()
eq = equipment_prices
# Tried to store forms in this dictionary but it look like a new instance
# is created on every form submission
ordersss = {}
if form.validate_on_submit():
ordersss[form.Type.data] = form.Price.data
print(form.Type.data, form.Price.data)
print(ordersss)
return redirect(url_for('equipment'))
return render_template('equipment.html', name='equipment', eq=eq, form=form)
#app.route('/equipment/cart', methods=['GET, POST'])
def cart():
return render_template('cart.html', name='cart')
Forms.py
Not sure if there needs to be function with in the actual form that adds the values to a dictionary
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
class AddEquipmentForm(FlaskForm):
Type = StringField('Type of Equipment',DataRequired())
Price = StringField('Price',DataRequired())
submit = SubmitField('Add equipment')
class OrderEquipmentForm(FlaskForm):
Type = StringField()
Price = StringField()
Order = SubmitField('Order')
# Should Dictionary go here?
# Not sure
def dict():
dict = {}
dict[Type] = Price
equipment.html
I would like to loop the element of the dictionary with in the Orders Table, if a dictionary is needed.
{% extends 'base.html' %}
{% block content %}
<div class="row">
<div class="col-6-sm">
<h1>Pricing</h1>
<table class='border'>
<thead class='border'>
<th style="width:200px;">Equipment</th>
<th style="width:200px; text-align:center;">Price</th>
<th></th>
</thead>
{% for quip in eq %}
<form method="post">
{{ form.hidden_tag() }}
<tr class ='border'>
<td>{{ quip }}</td>
<td style="text-align:center;"> <strong>${{ eq[quip] }}</strong></td>
<!-- Here I'm adding StringFields from the form but hiding them so they aren't displayed so I can submit the data somehow, hopefully to a dictionary. -->
<td style="display:none;">{{ form.Type(value=quip)}}</td>
<td style="display:none;">{{ form.Price(value=eq[quip]) }}</td>
<td><button class='btn btn-primary' type="submit">Add</button></td>
</tr>
</form>
{% endfor %}
</table>
</div>
<div class="col-6-sm">
<h1>Orders</h1>
<table>
<!-- This is where a loop of the dictionary elements of the items added would go -->
<tr>
<td></td>
<td></td>
</tr>
<button style='float:right' type="button" name="button" class='btn btn-info'>Order</button>
</table>
</div>
</div>
{% endblock %}

how do you change a database filter based on a link you click in django?

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.

Categories