Generate data when button/link is clicked Django - python

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.

Related

Blending the rendering of DataTableView and a standard view in Django

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...

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.

Django - Player URL not found despite being in urls.py

Over the last few days I have been working on building a Django web application for allowing users to make queries on a MLB Statistics database. I have some of the web app working fine, however I tried to implement a search function and ran into problems with the URL mapping. I tried to move on from this and instead work on getting the database to display information based on the link to the player that they click on, but I am running into the same issue with the URL's being dynamic based on the player's player_id. This portion only uses the People model which has player_id as its primary key.
Currently, I have an 'allPlayers.html' that lists every player in the database along with a link sending the player's player_id to the url as so:
allPlayers.html
{% extends "base_template.html" %}
{% block content %}
<h1>MLB Stats All Players</h1>
<p>Currently, there are : {{ num_players }} players listed in the database.</p>
<table style="width:100%">
<tr>
<th>First Name</th>
<th>Last Name</th>
<th></th>
</tr>
{% for player in players %}
<tr>
<td>{{ player.name_first }}</td>
<td>{{ player.name_last }}</td>
<td>More on {{ player.name_first }} {{ player.name_last }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
And the corresponding view for 'allPlayers.html':
def allplayers(request):
"""View function for allPlayers page of site."""
# Generate counts of people object
num_players = People.objects.count()
players = People.objects.all()
context = {
'num_players': num_players,
'players': players,
}
# Render the HTML template allPlayers.html w/ data in context variable
return render(request, 'allPlayers.html', context=context)
With just the above I have successfully created a page on my web app that lists each player in the database along with a link, and notice that I am trying to send the player_id through <a href='players/{{ player.player_id }}>. Currently the allPlayers portion works fine. However, things go south when I add the following playerInfo.html and corresponding view:
playerInfo.html
{% extends "base_template.html" %}
{% block content %}
{% if results %}
{% for player in results %}
<p>{{ player.name_first }} {{ player.name_last }}</p>
{% endfor %}
{% endif %}
{% endblock %}
And the view:
def player(request, pk=None):
if pk is not None:
print('Hello world')
print('pk :', pk)
#instance = get_object_or_404(People, player_id=pk)
results = People.object.filter(player_id=pk)
context = {
"results": results
}
return render(request, "playerInfo.html", context)
else:
print('Hello')
return render(request, 'playerInfo.html')
My idea was that the link noted earlier containing {{ player.player_id }} would match up with the following url and place the player_id value in for pk, as follows using the <int:pk> syntax instead of regex:
polls/urls.py
urlpatterns = [
path('', views.index, name='index'),
path('allPlayers', views.allplayers, name='allplayers'),
path('allTeams', views.allteams, name='allteams'),
path('search/', views.search, name='search'),
path('player/<int:pk>/', views.player, name='player'),
]
However, once I navigate to my 'allPlayers' page and click on one of the links for the player, say Hank Aaron (who has player_id aaronha01), I get the following Page not found (404) error:
Using the URLconf defined in baseballdb.urls, Django tried these URL patterns, in this order:
polls/ [name='index']
polls/ allPlayers [name='allplayers']
polls/ allTeams [name='allteams']
polls/ search/ [name='search']
polls/ player/<int:pk>/ [name='player']
admin/
The current path, polls/player/aaronha01/, didn't match any of these.
I have been having trouble with this for quite a bit now. If anyone has any advice and can point me in the right direction of how I'm thinking about this incorrectly or has a solution for me that would be seriously greatly appreciated! Thank you.
path('player/<int:pk>/' means only valid int pk would match. If your pk is not int and something like a valid slug - use path('player/<slug:pk>/' instead.
docs: https://docs.djangoproject.com/en/2.1/topics/http/urls/#path-converters
And my suggestion is to use {{ player.get_absolute_url }} or {% url 'player' player.id %} instead of building url manually.
Missing leading slash means "from here", not from website root:
https://webmasters.stackexchange.com/questions/56840/what-is-the-purpose-of-leading-slash-in-html-urls
There is a mismatch between <int:pk> in your path(), which expects an integer, and your player_id, which is a string like 'aaronha01'.
You can either use the pk everywhere, and have urls like /player/17/:
path('player/<int:pk>/', views.player, name='player'),
def player(request, pk):
instance = get_object_or_404(People, pk=pk)
context = {
"instance": instance,
}
return render(request, "playerInfo.html", context)
# Use pk in template when constructing URL
<td>More on {{ player.name_first }} {{ player.name_last }}</td>
Or you can use player_id everywhere, and have urls like /player/aaronha01/.
path('player/<slug:player_id>/', views.player, name='player'),
def player(request, player_id):
instance = get_object_or_404(People, player_id=player_id)
context = {
"instance": instance,
}
return render(request, "playerInfo.html", context)
# Use player_id in template when constructing URL
<td>More on {{ player.name_first }} {{ player.name_last }}</td>
As a next improvement, you can start using the {% url %} tag so that you aren't hardcoding the URLs anymore.
<a href="{% url "polls:player" player.player_id %}">
In the above, I've assumed that you have app_name='polls' in your polls/urls.py, and that you have decided to use player_id instead of pk in your url pattern.

flask with many buttons and database update

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>

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