Bouh10
Bouh10

Reputation: 297

Django: How to change the page at the click of a line?

I'm trying to make some views in Ddjango when i click on a line in a tag in HTMl and i need some advise and please take into account that i'm a beginner in Django. Indeed, i would like to change my view when i click on it, what will open a new view called like the Hash inside my tag. Let me explain you with this code called bap2pmonitoring.html:

{% load staticfiles %}
<!DOCTYPE html>
<html lang="fr">
<head>
    <link rel="stylesheet" type="text/css" href="{% static 'css/style.css' %}" />
</head>
<body>

<h1> BAP2P Monitoring</h1>


<table>
    <tr>
        <th width=550 height=20>Torrent Hash</th>
        <th width=720 height=20>Torrent Name</th>
        <th width=120 height=20>Size</th>
        <th width=170 height=20>Active Peers</th>
    </tr>

{% for torrent in torrents %}
        <p id="demo">
        <tr bgcolor=eeeeee> 
            <td width=550 height=20><a href="{{ url 'hash' torrent.Hash }}">{{ torrent.Hash }}</a></td>
            <td width=720 height=20>{{ torrent.Name }}</td>
            <td width=120 height=20>{{ torrent.Size }}</td>
            <td width=170 height=20></td>
    </tr>
        </p>
{% endfor %}

</table>

</body>
</html>

I obtain thus this result:

![enter image description here][1]

My idea is that when i click in one of these 2 lines, it render a new view with informations about this torrent with the hash of the torrent as url like this:

127.0.0.1:8000/torrents/606d4759c464c8fd0d4a5d8fc7a223ed70d31d7b

Following the Django tutorial, i tried lot's of things without success and then i tried a "onclick" to start one of my def in my view.py like this:

from django.shortcuts import render_to_response
from django.template import Template , Context
from polls.models import Torrent
# Create your views here.
# -*- coding: utf-8 -*-

def home(request):  
    return render_to_response('mysite/bap2pmonitoring.html', {'torrents':Torrent.objects.all()})


def details(request, torrent_hash):
    return render_to_response('mysite/detail_torrent.html', {'torrents':Torrent.objects.filter(hash=torrent_hash)})

I also tried to display the hash as an url like this in urls.py:

from django.conf.urls import patterns,include, url
from django.contrib import admin
from polls.models import Torrent

urlpatterns = patterns('polls.views',

     url(r'^torrents$', 'home', name = 'home'),
     url(r'^torrents/(?P<torrent_hash>)/$', 'details', name = 'hash'),
     url(r'^admin/', include(admin.site.urls)),
)

I don't understand how can i resolve this, any idea are welcomed and appreciated

Now i'm obtaining this error page:

NoReverseMatch at /torrents

Reverse for 'hash' with arguments '(u'606d4759c464c8fd0d4a5d8fc7a223ed70d31d7b',)' and keyword arguments '{}' not found. 1 pattern(s) tried: ['torrents/(?P<torrent_hash>)/$']

And this Traceback:

   Environment:


Request Method: GET
Request URL: http://127.0.0.1:8000/torrents

Django Version: 1.8.1
Python Version: 2.7.3
Installed Applications:
('django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'polls')
Installed Middleware:
('django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'django.middleware.security.SecurityMiddleware')


Template error:
In template /home/florian/Documents/mysite/templates/mysite/bap2pmonitoring.html, error at line 23
   Reverse for 'hash' with arguments '(u'606d4759c464c8fd0d4a5d8fc7a223ed70d31d7b',)' and keyword arguments '{}' not found. 1 pattern(s) tried: ['torrents/(?P<torrent_hash>)/$']

   13 :     <tr>



   14 :         <th width=550 height=20>Torrent Hash</th>



   15 :         <th width=720 height=20>Torrent Name</th>



   16 :         <th width=120 height=20>Size</th>



   17 :         <th width=170 height=20>Active Peers</th>



   18 :     </tr>



   19 : 



   20 : {% for torrent in torrents %}



   21 :         <p id="demo">



   22 :         <tr bgcolor=eeeeee> 



   23 :             <td width=550 height=20><a href=" {% url 'hash' torrent.Hash %} ">{{ torrent.Hash }}</a></td>



   24 :             <td width=720 height=20>{{ torrent.Name }}</td>



   25 :             <td width=120 height=20>{{ torrent.Size }}</td>



   26 :             <td width=170 height=20></td>



   27 :         </tr>



   28 :         </p>



   29 : {% endfor %}



   30 : 



   31 : </table>



   32 : 



   33 : </body>


Traceback:
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py" in get_response
  132.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/florian/Documents/mysite/polls/views.py" in home
  8.     return render_to_response('mysite/bap2pmonitoring.html', {'torrents':Torrent.objects.all()})
File "/usr/local/lib/python2.7/dist-packages/django/shortcuts.py" in render_to_response
  39.         content = loader.render_to_string(template_name, context, using=using)
File "/usr/local/lib/python2.7/dist-packages/django/template/loader.py" in render_to_string
  99.         return template.render(context, request)
File "/usr/local/lib/python2.7/dist-packages/django/template/backends/django.py" in render
  74.         return self.template.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
  209.                     return self._render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in _render
  201.         return self.nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py" in render
  903.                 bit = self.render_node(node, context)
File "/usr/local/lib/python2.7/dist-packages/django/template/debug.py" in render_node
  79.             return node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/defaulttags.py" in render
  217.                             nodelist.append(node.render(context))
File "/usr/local/lib/python2.7/dist-packages/django/template/defaulttags.py" in render
  507.                         six.reraise(*exc_info)
File "/usr/local/lib/python2.7/dist-packages/django/template/defaulttags.py" in render
  493.             url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app)
File "/usr/local/lib/python2.7/dist-packages/django/core/urlresolvers.py" in reverse
  579.     return force_text(iri_to_uri(resolver._reverse_with_prefix(view, prefix, *args, **kwargs)))
File "/usr/local/lib/python2.7/dist-packages/django/core/urlresolvers.py" in _reverse_with_prefix
  496.                              (lookup_view_s, args, kwargs, len(patterns), patterns))

Exception Type: NoReverseMatch at /torrents
Exception Value: Reverse for 'hash' with arguments '(u'606d4759c464c8fd0d4a5d8fc7a223ed70d31d7b',)' and keyword arguments '{}' not found. 1 pattern(s) tried: ['torrents/(?P<torrent_hash>)/$']

Upvotes: 2

Views: 4448

Answers (3)

Ralph King
Ralph King

Reputation: 1064

You'll need to:

change the context for your detail view to access only a single torrent, and also include your argument from the URL:

details(request, torrent_hash):
    return render_to_response('mysite/detail_torrent.html', {'torrent':Torrent.objects.filter(hash=torrent_hash)})

use a URL like this, which passes through your torrent hash to the view:

 url(r'^torrents/(?P<torrent_hash>)/$', 'details', name = 'hash'),

You'll also need your detail_torrent.html template, which you can then use your 'torrent' context in.

Edit to pre-empt another question:

In your main template, you can use this change to link through to the torrent. You are then passing the torrent.Hash variable through to your URL as the argument, which will be used for torrent_hash in the URL regex:

{% for torrent in torrents %}
    <p id="demo">
    <tr bgcolor=eeeeee> 
        <td width=560 height=20><a href="{% url 'hash' torrent.Hash %}">{{ torrent.Hash }}</a></td>
        <td width=710 height=20>{{ torrent.Name }}</td>
        <td width=110 height=20>{{ torrent.Size }}</td>
        <td width=110 height=20></td>
    </tr>
    </p>
{% endfor %}

Upvotes: 3

jg43
jg43

Reputation: 111

Thanks to Ralph's suggestion, I managed to do the same thing as the poster. However, with one tweak, namely, I am staying (intentionally) on the initial page, i.e., in the above example I am only using

'mysite/bap2pmonitoring.html'

where I invoke

<a href="{{ url 'hash' torrent.Hash }}">{{ torrent.Hash }}</a> 

(within the for loop)

the view consequently points back to 'mysite/bap2pmonitoring.html' instead of 'mysite/detail_torrent.html'

everything works well in terms of the link. However, once I click the link, and the result of the details view is displayed (correctly), the links of the loop disappear. Everything else of the initial page remains. Is there a way to prevent this, i.e., keep the links?

(The idea is to create a pannel and to display the details below, being able to update the details by the links of the pannel)

Upvotes: 0

kylieCatt
kylieCatt

Reputation: 11039

That onlick attribute is not going to call your server side views functions. It is a JavaScript even handler so it is going to look for a JS function named details() since it doesn't look like you have one it's not going to do anything. you can confirm this by opening up your browsers development tools and going to the "Console" tab. Once you're there click on of your rows and you'll see something that looks like this:

Uncaught ReferenceError: details is not defined

You will need to write a JS function that will back to your server and so your server can send a new page to be rendered. I would strongly recommend using jQuery for this as it will make your life much simpler.

First you need to modify your HTML as there are few things wrong:

{% for torrent in torrents %}
    <tr class="torrent" id="{{ torrent.Hash }}" > 
      <td width=550 height=20>{{ torrent.Hash }}</td>
      <td width=720 height=20>{{ torrent.Name }}</td>
      <td width=120 height=20>{{ torrent.Size }}</td>
      <td width=170 height=20></td>
    </tr>
{% endfor %}

id attributes on HTML elements should be unique and we will be using it later in our JS to get the right URL. There is no need to wrap <tr> in a <p> tag so let's get rid of it. I added a class to make our lives a little easier when writing the JS.

Now the JS:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
  $(".torrent").on('click', function(){
    var hash = $(this).attr('id');
    window.location.href = '/torrents/' + hash;
  });
</script>

Be sure to include this just above your closing <body> tag in your template.

Alternatively you could not add a CSS class and use this jQuery selector $('tr') but only do so if this will be the only table on the page.

This will create a URL for you and then open that URL when you click anywhere on the table row.

urlpatterns = patterns('polls.views',
     url(r'^torrents$', 'home', name = 'home'),
     url(r'^torrents/(?P<torrent_hash>)/$', 'details', name='hash'),  # this line
     url(r'^admin/', include(admin.site.urls)),
)

You will need to adjust the line I indicated so that it will work properly. And finally modify your view to accept your new parameter:

def details(request, torrent_hash):
    return render_to_response('mysite/detail_torrent.html', {'torrents':Torrent.objects.get(Hash=torrent_hash)})

EDIT: One more step, to make it obvious to users that they can click on the table row to go to a new url you will want this in your CSS:

.torrent:hover {
  cursor: pointer;
}

Upvotes: 1

Related Questions