Django how to pass link specific url to another html page showing static images

I have table of tickers on one HTML page, and four charts displayed on another HTML page. These charts come from my static/images folder full of hundreds of images named by each ETF’s benchmark index ticker. If I click the ETF ticker “PSCD” in the first row of the table, how can it be linked to another HTML page named charts.html which shows four charts whose filenames contain the ETF’s benchmark index ticker, example: chart1/S6COND.jpg, chart2/S6COND.jpg, chart3/S6COND.jpg, chart4/S6COND.jpg. ← In this example, I hardcoded S6COND.jpg into the link, and it works…but I need it to be dynamically tied to the index ticker of whatever etf ticker row I click on in the table. The index ticker for each ETF for each row in the table is included in my models.py which you can see below.

In the charts.html code example below, I hardcoded S6COND into the image tag but I want this dynamically linked.

enter image description here

Below you will see my table.html page showing my table from above. Next is the charts.html where I would like the etf_ticker that was clicked in that table to be entered into the image tags such as <img src="{% static 'myapp/images/chart1_S6COND.jpg' %}" alt="chart1"/></div> where you see I have hardcoded “S6COND” into the image tag. But I need this to be dynamic, from which you click on the link in table.html, and it gets inserted into the image tag in charts.html.

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><a href="{% url 'myapp:charts' %}" target="_blank">{{i.etf_ticker}}</a></td>
        <td><a href="{% url 'myapp:charts' %}" target="_blank">{{i.etf_name}}</a></td>
        <td><a href="{% url 'myapp:charts' %}" target="_blank">{{i.index_name}}</a></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>

charts.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Charts</title>
    {% load static %}
    <link rel="stylesheet" type="text/css" href="{% static 'myapp/css/charts_style.css' %}">
    <style type="text/css">
        ul {
            list-style-type: none;
            margin: 0;
            padding: 0;
        }
    </style>
</head>
<body>
<nav>
  <ul>
    <li><a class="nav" href="{% url 'myapp:index' %}">Home</a></li><br><br>
    <li><a class="nav" href="{% url 'myapp:table' %}">Table</a></li><br>
  </ul>
</nav>
<div class="container">
    <div class="box"><img src="{% static 'myapp/images/chart1_S6COND.jpg' %}" alt="chart1"/></div>
    <div class="box"><img src="{% static 'myapp/images/chart2_S6COND.jpg' %}" alt="chart2"/></div>
    <div class="box"><img src="{% static 'myapp/images/chart3_S6COND.jpg' %}" alt="chart3"/></div>
    <div class="box"><img src="{% static 'myapp/images/chart4_S6COND.jpg' %}" alt="chart4"/></div>
</div>
</body>
</html>

urls.py

from django.urls import path
from . import views
from .views import ChartView

app_name = 'myapp'
urlpatterns = [
    path('', views.index, name='index'),
    path('table/', views.table, name='table'),
    path('charts/', ChartView.as_view(), name='charts'),
]

models.py

from django.db import models


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=200)

views.py

from django.shortcuts import render
from django.views.generic import TemplateView
from .models import Table


def index(request):
    return render(request, 'index.html')


def table(request):
    data = Table.objects.all().values()
    context = {'d': data}
    return render(request, 'table.html', context)


class ChartView(TemplateView):
    template_name = 'charts.html'

You typically pass selections from one view to another through URL parameters.

Build your link url using the ticker symbol (or the pk of the table containing that symbol) as a parameter in the second view’s URL.

Your second view can then build the page with the links to the proper images based on that symbol.

Could you point me to an example of how to do that?

I tried:

table.html

<a href="{% url 'myapp:charts' i.index_ticker %}" target="_blank">{{i.etf_ticker}}</a>

views.html

class ChartView(TemplateView):
    template_name = 'charts.html'

    def get(self, request, ticker=None):
        if ticker:
            return render(request, self.template_name, {'ticker': ticker})
        else:
            return render(request, self.template_name)

charts.html

<div class="container">
    <img src="{% static 'myapp/images/chart1_'|add:ticker|add:'.jpg' %}" alt="chart1"/>
    <img src="{% static 'myapp/images/chart2_'|add:ticker|add:'.jpg' %}" alt="chart2"/>
    <img src="{% static 'myapp/images/chart3_'|add:ticker|add:'.jpg' %}" alt="chart3"/>
    <img src="{% static 'myapp/images/chart4_'|add:ticker|add:'.jpg' %}" alt="chart4"/>
</div>

But this raised a NoReverseMatch exception on table.html at the link I included in this comment.

NoReverseMatch at /myapp/table/
Reverse for 'charts' not found. 'charts' is not a valid view function or pattern name.

What does your urls.py file look like for this app? The error is saying that you don’t have a url defined with a name of ‘charts’.

Also note that you will need to change that url to accept a parameter, and that you access parameters in CBV in self.kwargs, not as function parameters.

Looks like this.

urls.py

from django.urls import path
from . import views
from .views import ChartView

app_name = 'myapp'
urlpatterns = [
    path('', views.index, name='index'),
    path('table/', views.table, name='table'),
    path('charts/<str:ticker>', ChartView.as_view(), name='charts')
]

Would you please post the entire error with traceback that you are getting? I don’t see anything wrong with what you’ve posted, so I’m hoping the full message with traceback provides some clues.

(Side note of no relevance to this current issue: I noticed in your template you have an if d before your for i in d. That’s really not necessary to do that. If d doesn’t exist or is an empty iterable, the loop isn’t going to execute.)

Here is the traceback. Good to know on the unnecessary if statement.

Environment:


Request Method: GET
Request URL: http://127.0.0.1:8000/myapp/table/

Django Version: 4.0
Python Version: 3.8.12
Installed Applications:
['myapp.apps.TableConfig',
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']


Template error:
In template mysite\myapp\templates\myapp\myapp.html, error at line 51
   Reverse for 'charts' not found. 'charts' is not a valid view function or pattern name.
   48 :     {% if d %}
   49 :     {% for i in d %}
   50 :       <tr>
   51 :         <td><a href="{% url 'myapp:charts' i.index_ticker %}" target="_blank">{{i.etf_ticker}}</a></td>
   52 :         <td><a href="{% url 'myapp:charts' i.index_ticker %}" target="_blank">{{i.etf_name}}</a></td>
   53 :         <td><a href="{% url 'myapp:charts' i.index_ticker %}" target="_blank">{{i.index_name}}</a></td>
   54 :       </tr>
   55 :     {% endfor %}
   56 :     {% endif %}
   57 :     </tbody>


Traceback (most recent call last):
  File "django\core\handlers\exception.py", line 47, in inner
    response = get_response(request)
  File "django\core\handlers\base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "mysite\myapp\views.py", line 13, in table
    return render(request, 'table.html', context)
  File "django\shortcuts.py", line 19, in render
    content = loader.render_to_string(template_name, context, request, using=using)
  File "django\template\loader.py", line 62, in render_to_string
    return template.render(context, request)
  File "django\template\backends\django.py", line 61, in render
    return self.template.render(context)
  File "django\template\base.py", line 176, in render
    return self._render(context)
  File "django\template\base.py", line 168, in _render
    return self.nodelist.render(context)
  File "django\template\base.py", line 977, in render
    return SafeString(''.join([
  File "django\template\base.py", line 978, in <listcomp>
    node.render_annotated(context) for node in self
  File "django\template\base.py", line 938, in render_annotated
    return self.render(context)
  File "django\template\defaulttags.py", line 295, in render
    return nodelist.render(context)
  File "django\template\base.py", line 977, in render
    return SafeString(''.join([
  File "django\template\base.py", line 978, in <listcomp>
    node.render_annotated(context) for node in self
  File "django\template\base.py", line 938, in render_annotated
    return self.render(context)
  File "django\template\defaulttags.py", line 214, in render
    nodelist.append(node.render_annotated(context))
  File "django\template\base.py", line 938, in render_annotated
    return self.render(context)
  File "django\template\defaulttags.py", line 442, in render
    url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app)
  File "django\urls\base.py", line 86, in reverse
    return resolver._reverse_with_prefix(view, prefix, *args, **kwargs)
  File "django\urls\resolvers.py", line 729, in _reverse_with_prefix
    raise NoReverseMatch(msg)

Exception Type: NoReverseMatch at /myapp/table/
Exception Value: Reverse for 'charts' not found. 'charts' is not a valid view function or pattern name.

I’m really fishing here - I’m sure I’m overlooking something but I have no idea what.

Everything looks right to me from what I’m seeing.

Is there any chance that there’s a space or other “url-special” character (e.g. #, %, /, &, etc) in index_ticker?

Also, if you have debug=True and you enter an incorrect url, Django will display a web page showing all the valid patterns being matched. You might want to enter a totally-wrong URL and verify that charts shows up in the list of urls being searched - there might be something more fundamentally wrong here.

i.index_ticker returns just the index ticker of that ETF ticker. I’ve included below after the 404 error quote, examples showing code that worked in at least showing a chart, or 4 charts, but never 4 charts shown based on the ETF ticker of the table row the user clicks on. It broke on this line when I added the i.index_ticker to the URL tag. If I remove i.index_ticker from this tag, it works in directing me to the charts.html page.

<a href="{% url 'myapp:charts' i.index_ticker %}" target="_blank">{{i.etf_ticker}}</a>

These are the URL patterns Django when I tried a wrong URL:

Page not found (404)
Using the URLconf defined in mysite.urls, Django tried these URL patterns, in this order:

admin/
myapp/ [name='index']
myapp/ table/ [name='table']
myapp/ charts/<str:ticker> [name='charts']
The current path, myapp/charts/, didn’t match any of these.

These lines worked in terms of charts.html loading with a chart or charts. But unfortunately, either only 1 dynamically linked chart is shown as jpg image alone in browser or if I hardcode the index_ticker into the URL, it’ll show my 4 charts but the charts need to be tied to ETF ticker the user clicks in the table.

This one only shows 1 chart.

<a href="{% static '/myapp/images/chart1_'|add:i.index_ticker|add:'.jpg' %}" target="_blank">{{i.etf_ticker}}</a>

This one works to link to the charts.html page but does not tell charts.html which specific charts I want displayed according to the index_ticker.

<a href="{% url 'myapp:charts' %}" target="_blank">{{i.etf_ticker}}</a>

This works in charts.html because I hardcoded S6COND into the URL myself and only shows a single jpg image of S6COND, not dynamically linked.

<div class="box"><img src="{% static 'myapp/images/chart1_S6COND.jpg' %}" alt="chart1"/></div>

Unfortunately, that by itself doesn’t really mean anything to me.

Is there any chance that any of the entries in that column contain any “url-hostile” characters? (That sort of situation is why it’s generally preferred to pass the pk of the reference as the url parameter instead of arbitrary strings. But if you’re sure that none of the entries has any of those characters then this isn’t the issue.)

Here are the index tickers. None of them have url-hostile characters. Just alpha-numeric characters.

Try this - remove the .values() clause from your query in the table view. Allow Django to pass the objects directly into the template rendering engine.

I removed .values() clause from table view and still get the Reverse for 'charts' not found. 'charts' is not a valid view function or pattern name.

views.py now looks like this:

from django.shortcuts import render
from django.views.generic import TemplateView
from .models import Table


def index(request):
    return render(request, 'index.html')


def table(request):
    data = Table.objects.all()
    context = {'d': data}
    return render(request, 'table.html', context)


class ChartView(TemplateView):
    template_name = 'charts.html'

    def get(self, request, ticker=None):
        if ticker:
            return render(request, self.template_name, {'ticker': ticker})
        else:
            return render(request, self.template_name)

I don’t know what to say at this point. I can’t recreate this issue in my environment based upon what you’ve got here and I can’t think of what you might have in your project that could cause this to happen - especially if this works without the parameter. That’s why I’m focused so much on what that parameter is - I gotta believe it’s somehow related to that parameter.

In the category of “trying anything to see if it works”, I’d probably be trying things like:

  • Change the parameter from i.index_ticker to i.pk, and the url parameter from str to int
  • Try a more trivial template with a constant value as a parameter
  • Try a more trivial template with a value passed in through the context

If it helps, here is the actual project Github page showing you the app with the changes you suggested so far.

What I’m looking at in branch1 is vastly different from what you’ve been reporting here.

Specifically, your url tag entries do not match the url definition. You’re got 'forecast:forecast_charts' in the template, but the name entry is name='charts'

Yea, I had removed all references to the word “forecast” to make my code example as generic as possible. But this is the actual project I am working on. It’s all the same, but just with the word “forecast” everywhere.

I am going to try to create a model of images and see if I can create a view with context variable referring to that model of images, and see what happens. I will of course share any solution I might find.

Thank you for your time even though a solution couldn’t be found!

If what you’ve got in the repo is what you’re actually working with, then you should be able to just fix the name entry in the urls.py file.

I figured out the issue. Thanks for your help.