Django how to hyperlink to images in static folder by ticker symbol? - python

I have a table of ETF tickers, ETF names, and their Index names. I want each entry in the table to be clickable and linked to their associated images in the static/images folder. Each image is named after each ETF's index ticker. So when a user clicks on, for example, the first entry ETF ticker "PSCD" links to 'static/myapp/images/sample_regression_S6COND.jpg'. The substring in the link "S6COND" is the part I need as a relative link. Each ETF ticker has a different Index ticker. These Index tickers are in a model associated with the table.
In my table.html page, when I hardcode the link to the static image <td>{{i.etf_ticker}}</td> (see how I typed "S6COND" into the link?), it works, but not when I try to turn it into a relative link {{i.index_ticker}} like <td>{{i.etf_name}}</td>. My static files in correctly placed inside my app folder and includes images, css, and js folders. All images are inside the static/myapp/images folder.
table.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ETF Table</title>
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'myapp/css/table_style.css' %}">
<style type="text/css"></style>
</head>
<body>
<div class="container">
<table id="table" class="table table-dark table-hover table-striped table-bordered table-sm">
<thead>
<tr>
<th data-sortable="true">ETF Ticker</th>
<th>ETF Name</th>
<th>Index Name</th>
</tr>
</thead>
<tbody>
{% if d %}
{% for i in d %}
<tr>
<td>{{i.etf_ticker}}</td>
<td>{{i.etf_name}}</td>
<td>{{i.index_name}}</td>
</tr>
{% endfor %}
{% endif %}
</tbody>
</table>
<script>
$('#table').DataTable({
"bLengthChange": true,
"lengthMenu": [ [20, 50, 100 -1], [20, 50, 100, "All"] ],
"iDisplayLength": 20,
bInfo: false,
responsive: true,
order: [[4, 'desc']],
});
</script>
</div>
</body>
</html>
views.py
def table(request):
data = Table.objects.all().values()
context = {'d': data}
return render(request, 'table.html', context)
models.py
class Table(models.Model):
etf_ticker = models.CharField(max_length=10)
etf_name = models.CharField(max_length=200)
index_name = models.CharField(max_length=200)
index_ticker = models.CharField(max_length=10)

Create your url in the following manner:
{{i.etf_name}}
I've broken your url into 3 parts. The first and last parts are simple strings. The middle part contains your ticker. The | is used to denote that we're using one of Django templating language's filters. The template we're using is add. It is used to add stuff to whatever comes before the pipe. If we were dealing with numbers, it would add them mathematically, but since we're using strings, it concatenates the 2 strings instead. Similarly the last part is concatenated to the first two parts and ends up generating the url you require.
The reason why your method wasn't working was that you were trying to pass a variable {{i.index_ticker}} to a string. This was creating a url that literally contains a formatterd version of {{i.index_ticker}}. Which is why you were probably getting %7B%7Bi.index_ticker%7D%7D in the url.

Related

Table order messed in Firefox, but works fine in other browsers

I have a table that I sort by date, it works fine in EDGE and Chrome, but the order is messed in Firefox. A series of rows that should be on top got moved down to the bottom.
HTML:
<div class="row mt-4">
<div class="col-12">
<div class="card">
<h6 class="card-header">Change Log Items</h6>
<div class="card-body">
<table id="changes" class="table table-striped table-hover table-bordered table-sm">
<thead class="table-dark">
<tr class="sticky">
<th>Title</th>
<th>Component</th>
<th>Date Committed</th>
<th>Jira Link</th>
<th>Details</th>
</tr>
</thead>
<tbody>
{% for log in logs %}
<tr>
<td>{{log.title}}</td>
<td>{{log.component}}</td>
<td>{{log.date_added}}</td>
<td>{% if log.jira_number %}<a class="general" href="https://jira.kinaxis.com/browse/{{log.jira_number}}" target="_blank">{{log.jira_number}}{% endif %}</a></td>
<td>{% if log.details %}{{log.details}}{% elif not log.details and log.jira_number %}See Jira ticket{% endif %}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
View:
#login_required
def change_log(request):
logs = ChangeLog.objects.all().order_by('date_added')
return render(request, 'help\changelog.html', {'logs': logs})
Any information helps! :)
Update:
I realized the problem was caused by the jQuery corresponding to the HTML element:
<script type="text/javascript">
$(document).ready(function () {
const exceptions = $('#changes').DataTable({
"order": [[ 2, "desc" ]],
"pageLength": 50,
"columnDefs": [{"type": "date", "targets": [2],}], // Sort by Date properly
});
});
</script>
Seems like DataTable has some issues with FF?
Changing the order in "order": [[ 2, "desc" ]]" to asc doesn't work for FF.
Most likely, the date format you are using is not supported by Firefox, as "the date formats supported by each browser vary significantly". In such cases, one could use the "ultimate" date / time ordering plug-in for DataTables, as suggested here. To do that, include the following libraries in your HTML file, as described in the above link:
<script type="text/javascript" charset="utf8" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.4/moment.min.js"></script>
<script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/plug-ins/1.11.5/sorting/datetime-moment.js"></script>
Next, register the date format(s) that you wish DataTables to detect and order using the $.fn.dataTable.moment(format) method. For instance:
$(document).ready(function() {
$.fn.dataTable.moment( 'HH:mm MMM D, YY' );
...
DataTables will automatically detect the column(s) with date data, by checking to see if the data in a column matches any of the given types. You can register multiple date formats, if a DataTable contains more than one date columns.
Try explicitly adding "ordering: true" to your DataTable() instantiation, like so:
<script type="text/javascript">
$(document).ready(function () {
const exceptions = $('#changes').DataTable({
ordering: true, # add this line
"order": [[ 2, "desc" ]],
"pageLength": 50,
"columnDefs": [{"type": "date", "targets": [2],}], // Sort by Date properly
});
});
</script>
More a suggestion than an answer, but didn't want to paste this code in the comments.

Injecting data into html using Flask

I have a flask app, about saving strings into some db files.
I have a base.html file which is like navbar which i extend to every page. That navbar has a lots of links which require a specific string that the user has to enter, so i wanna know if there's a way to inject strings into that base.html file, cuz i can't make a route for a navbar base file right?
Navbar base file down below
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/static/css/base.css">
<title>
BukkitList - {% block title %}{% endblock %}
</title>
</head>
<body>
<div class="NAV_B Hidden" id="MENU">
<div class="NAV_B_LINKS">
<img src="/static/assets/img/cube.png" alt="">
<a class="SUS" href="/">Home</a>
</div>
<div class="NAV_B_LINKS">
<img src="/static/assets/img/list.png" alt="">
<a class="/List{{UserId}}" href="/List">List</a>
</div>
<div class="NAV_B_LINKS">
<img src="/static/assets/img/add.png" alt="">
<a class="/Task_Add/{{UserId}}">Add Task</a>
</div>
<div class="NAV_B_LINKS">
<img src="/static/assets/img/settings.png" alt="">
<a class="SUS">Settings</a>
</div>
</div>
<div class="NAV_S" id="NAV">
<img src="/static/assets/img/cube.png" alt="">
<h3>{% block navtitle %}
{% endblock %}
</h3>
<img src="/static/assets/img/menu.png" alt="" onclick="Menu()">
</div>
{% block main %}
{% endblock %}
</body>
<script src="/static/js/base.js"></script>
</html>
Yes i need that UserId to be injected.
the question is not very understandable of where the user is inputting the {{UserID}} but from what I understand that there is that userID that you can select from the db in the Python file and you want to pass it into the HTML page or if you have a sign-in in your page, you can grab that ID when they sign in using flask_session either way if you need to pass that userID from the Python file you will need to include it in your return, so in python it will look like that if you are using session:
#app.route("/")
def main():
UserIDpy = Session["YourSessionVar"]
return render_template("YourHTMLpage.html", UserID = UserIDpy)
The UserID is the var name that will be passed into the HTML page and UserIDpy is the var name that what UserID saved at.
So that code will replace all of {{ UserID }} you have at you HTML page
I believe you can do this with Flask's session variable. It allows you to create and update a global variable that can be referenced in templates even when you don't render them directly. This is similar to Lychas' answer, but should be more suited for your purpose.
Create/update a session variable in your login route (or wherever you want to update this value) with this line:
session['UserId'] = your_id_value_here
You can then use this session variable in your jinja templates with something like the following:
<a class="/Task_Add/{{ session['UserId'] }}">Add Task</a>
(Note, if you are not already using session, you will need to import it with from Flask import session.)

Django: Get a table into Django view

I have Django model that contains data ("Name" and "Status") for 10 people. I display this model in a DataTable with checkboxes and if I check a box it changes the Class into selected, e.g. <tr role="row" class="odd selected"
The user makes a selection from the DataTable and press a button ("Send selection by email"). The selection will go into a Django View. I will write code that filter out those contains a selected, obtain its PK and send an email with info.
However, I have problem in the first step, to get the DataTable object into the view.
A similar approach would have been to use a Multiselect, but here I want the look of a table and not a form box.
My attempted solution is to put form tags around the DataTable and then read the table to filter out all that are selected.
Problem I currently have is that I cannot get the DataTable into the views.py.
So my question is: How do I access the table in Django View?
I have tried both POST and GET within below, but request object returns as None
$('#datatable').DataTable({
responsive: true,
columnDefs: [{
orderable: false,
className: 'select-checkbox',
targets: 0
}],
select: {
style: 'multi',
selector: 'td:first-child',
// selectRow: true
},
order: [
[1, 'asc']
],
language: {
searchPlaceholder: 'Search...',
sSearch: '',
lengthMenu: '_MENU_ items/page',
}
});
<!DOCTYPE html>
<html lang="en">
<head>
<title>Bootstrap Example</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script src="https://cdn.datatables.net/1.10.20/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/select/1.3.1/js/dataTables.select.min.js"></script>
</head>
<body>
<div class="container">
<form method="post" action="{% url 'product-send2' %}">
{% csrf_token %}
<div class="table-wrapper">
<table class="form-control table display responsive" id='datatable' style="width:100%;">
<thead>
<tr>
<th>Send</th>
<th>Name</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{% for object in object_list %}
<tr>
<td></td>
<td>{{ object.name }}</td>
<td>{{ object.status }}</td>
<tr>
{% endfor %}
</tbody>
<tfoot>
</tfoot>
</table>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</body>
</html>
In the Urls
path('product/send/', send_product2, name='product-send2')
and in the views
def send_product2(request):
recipients = request.POST.get('datatable')
print(recipients)
return HttpResponseRedirect('/product/list')
I have tried variants such as
recipients = request.GET.get('datatable')
and
recipients = request.POST.get('datatable', False)
I cannot get hold of the "object" and don't really know how to debug it.
In the end, it should work as a multiselect for the form (that will be sent by email).
I hope I can help with some hints how to progress.
Thanks!
When I print(request.__dict__) it looks like below
: <SimpleLazyObject: <function AuthenticationMiddleware.process_request.<locals>.<lambda> at 0x7f907ab5f680>>, '_messages': <django.contrib.messages.storage.fallback.FallbackStorage object at 0x7f907ab82b10>, '_body': b'csrfmiddlewaretoken=xxx_length=10', '_post': <QueryDict: {'csrfmiddlewaretoken': ['xxxxx'], 'datatable_length': ['10']}>, '_files': <MultiValueDict: {}>, 'csrf_processing_done': True}
you can not submit an entire table in a form, especially based on id tag. From the code you posted it looks like you configured your datatable without event handlers.
From: https://editor.datatables.net/examples/inline-editing/submitButton.html
dom: "Bfrtip",
ajax: "../php/staff.php",
columns: [
{
data: null,
defaultContent: '',
className: 'select-checkbox',
orderable: false
},
{ data: "first_name" },
{ data: "last_name" },
{ data: "position" },
{ data: "office" },
{ data: "start_date" },
{ data: "salary", render: $.fn.dataTable.render.number( ',', '.', 0, '$' ) }
],
order: [ 1, 'asc' ],
select: {
style: 'os',
selector: 'td:first-child'
},
buttons: [
{ extend: "create", editor: editor },
{ extend: "edit", editor: editor },
{ extend: "remove", editor: editor }
]
and then added a submit button that actually tries to pull all the elements with name tag in the form dom sub-tree and sends those to the back-end.
In order to achieve what you want you need to create a custom event handler in the front-end that is hooked to the checkbox(or use functions integrated in the DataTable plugin) then generate a form on the fly with javascript where you add the relevant information(the pk of the selected record/s I assume). Submitting the newly generated form will result in a valid POST request that you can handle in the view.
Given all above, I would recommend to avoid using such mechanics in general. POST/GET that are not REST based lead to the regeneration of the entire page which is a bad thing to do when dealing with large interactive tables.

View to Download FileField From Django

I have files which are saved to the MEDIA_ROOT - and I am displaying the file paths as URLs in a table in my UI. I would like for these files to download when the user clicks the link in the table. However, when that happens I get an error because I don't have a URL or View defined to handle this I suppose. Problem is, I'm not really sure where to start - any suggestions. Below is my model, and the .html which displays the table and the link.
models.py
class Orders(models.Model):
...
order_file = models.FileField(upload_to='web_unit', null=True, blank=True)
...
def __str__(self):
return self.reference
index.html
<div class="table-responsive">
<table id="main_table" class="table table-striped table-bordered" cellspacing="0" style="width="100%">
<thead>
<tr>
....
</thead>
<tbody>
{% for orders in orders %}
<tr>
<td>
<!-- Update book buttons -->
<button type="button" class="update-book btn btn-sm btn-primary" style="color: #FFCF8B; border-color: #FFCF8B; background-color: #FFF;" data-id="{% url 'order_update' orders.pk %}">
<span class="fa fa-pencil"></span>
</button>
</td>
....
<td>Download</td> #this is the link
</tr>
{% endfor %}
</tbody>
</table>
When the link in the table is clicked - I'd like for the file to be downloaded - I need help on how to define the URL and the View to make this happen.
This has been marked as a duplicate a few times now - but I don't believe it is. The link that I have been referred to only shows a view. I don't understand how I am to trigger that view using a url since there will be many download links in the same screen. How does the view know which file link I have clicked on? Wouldn't that need to leverage the URL somehow?
First, don't do {% for orders in orders %}; instead do {% for order in orders %}
Then this should work (assuming order_file is the field name you didn't show in the model)
<td>Download</td>

get_template_attribute not displaying data in html

i came across get_template_attribute in the flask api and thought of it as a great way to achieve partial page rendering.
so the goal was
create a 2 layer menu-page layout
menu should be static
on click of
menu, page should be shown dynamically without refreshing the entire
page
so i did something like so
LandingPage.html
<html>
<head>
<style>
html,body{
height:100%;
}
</style>
<script type="text/javascript">
function finalConfirmationToStartJob() {
alert('in here')
$.ajax({
type : 'GET',
url : 'home2',
data : ''
});
};
</script></head>
<body>
<table border=1 height=100% width=100%>
<tr><td colspan='2'/></tr>
<tr>
<td width=15%>
<ul>
<li>ABC</li>
<ul>
<li>ABC1</li>
<li>ABC2</li>
<li>ABC3</li>
</ul>
<li>DEF</li>
<li>GHI</li>
<li>JKL</li>
</ul>
</td>
<td>
{% macro hello(name) %}Hello {{ name }}!{% endmacro %}
how are you darlings!!! {{hello()}}
</td>
</tr>
<tr><td colspan='2'/></tr>
</table>
</body>
</html>
Controller
#app.route("/home")
def goto_home():
return render_template('/LandingPage.html')
#app.route("/home2")
def try_out_macro():
print 'hellooo elloo'
hello = get_template_attribute('/LandingPage.html', 'hello')
return hello('World')
However when i do click on the action link, even though the controller actually returns perfect data , the data is not displayed on the screen.
When i hit the url /home2 i do get perfect data, however on click on action link nothing happens on the html
Can someone please help me, i am not sure what i am doing wrong
PS : i got it to work using innr html and div combination, however i would still like to know why the above doesnt work.

Categories

Resources