ccsv
ccsv

Reputation: 8659

Using linkify option on Django_tables2 columns to create links

I want to add a link to my listview using linkify in the Columns of the API Reference. I am using Django 2 with Django_tables2 v 2.0.0b3

I have a URL with two context variables name, which is passed from the ListView and the slug field species:

URL.py

app_name = 'main'

urlpatterns = [
#The list view
path('genus/<slug:name>/species/', views.SpeciesListView.as_view(), name='species_list'),
# The Detail view
path('genus/<name>/species/<slug:species>', views.SpeciesDetailView.as_view(), name='species'),
]

The DetailView is currently accessible if I manually type the URL.

I want to use the option where I can enter a tuple with (viewname, args/kwargs).

For the tables.py I tried:

class SpeciesTable(tables.Table):
    species =tables.Column(linkify=('main:species', {'name': name,'slug':species}))

This gave a NameError: name 'species' is not defined.

species =tables.Column(linkify=('main:species', {'name': kwargs['name'],'slug':kwargs['species']}))

This gave a NameError: name 'kwargs' is not defined.

I also tried changing the following variables to strings:

species =tables.Column(linkify=('main:species', {'name': 'name','slug':'species'}))
species =tables.Column(linkify=('main:species', {'name': 'name','slug':'object.species'}))

These attempts gave a NoReverseMatch Reverse for 'species' with keyword arguments '{'name': 'name', 'slug': 'species'}' not found. 1 pattern(s) tried: ['genus\\/(?P<name>[^/]+)\\/species\\/(?P<species>[-a-zA-Z0-9_]+)$']

Formatting it as any of the following will give a SyntaxError:

species =tables.Column(kwargs={'main:species','name': name,'slug':species})
species =tables.Column(args={'main:species','name': name,'slug':species})
species =tables.Column(kwargs:{'main:species','name': name,'slug':species})
species =tables.Column(args:{'main:species','name': name,'slug':species})

How would I add a link similar to {% url "main:species" name=name species =object.species %}? Currently there are no example in the docs to do this.

Upvotes: 4

Views: 6644

Answers (2)

Richard Scholtens
Richard Scholtens

Reputation: 1023

Alternative option for the linkify parameter

After many tries I never got the linkify parameter option working the way I wanted. However, I did find a way to achieve the same result.

You can add a render_foo function. For instance, if you want to render an ID with a link one can add the render_id function to their table class. This function will then overwrite the existing rendering for the attribute ID.

More information about this can be found on: https://django-tables2.readthedocs.io/en/latest/pages/custom-data.html

models.py

# models.py

import django_tables2 as tables
from django.urls import reverse


class Person:
   name = model.CharField(default='Jeffrey Lebowski', max_length=256)
   nick_name = model.CharField(default='the Dude', max_length=256)
   hates_hearing = model.CharField(default="Where's the money Lebowski?", max_length=256)


class PersonTable(tables.Table):
    class Meta:
        model = Person
        template_name = "django_tables2/bootstrap.html"
        fields("id", "name", "nick_name", "hates_hearing", )
   
    def render_id(self, record):
        """
        This function will render over the default id column. 
        By adding <a href> HTML formatting around the id number a link will be added, 
        thus acting the same as linkify. The record stands for the entire record
        for the row from the table data.
        """
        return format_html('<a href="{}">{}</a>',
                           reverse('example-view-name',
                           kwargs={'id':, record.id}),
                           record.id)
   

For this to work one would also need to specify the view, url, and template.

views.py

# views.py

from django_tables2 import SingleTableView

class ExampleTableView(SingleTableView):
    model = Person
    table_class = PersonTable
    template_name = "app_name/example.html"
    object_list = Person.objects.all()

urls.py

# urls.py

from django.urls import path
from . import views


urlpatterns = [
    path('<int:id>', views.detail, name="example-view-name"),
]

example.html

# templates/app_name/example.html

{% load static %}

<!DOCTYPE html>
<html>
<head>
   <meta charset="UTF-8">
   <title>EXAMPLE HTML</title>
</head>
<body>
   <section>
       <div>
           <h1>EXAMPLE TABLE</h1>
           <p>Here one can find the result of the django-tables2 output</p>
           {% render_table table %}
       </div>
   </section>
</body>
<footer>
    <p>That's it.</p>
</footer>
</html>

Please note, one has to add django-tables2 to the installed apps list. Otherwise the template does not work.

Maybe this a good alternative. If someone has any comments or improvements, let me know.

Upvotes: 1

Jieter
Jieter

Reputation: 4229

Try to think from the perspective of a row. In each row, the table needs the species of that row. The mechanism used in django-tables2 for that is an accessor. It enables you to tell django-tables2 the value you want it to use for a certain value. You cannot use variables (like name and species for that, because you want them to be retrieved from each record.

So using the accessor (usually abbreviated with A), your first example looks like this:

class SpeciesTable(tables.Table):
    species = tables.Column(linkify=('main:species', {'name': tables.A('name'),'slug': tables.A('species')}))

The concept of Accessors is usable in multiple places, also to change the value you want to render in a column.

I'd suggest defining get_absolute_url methods on your models though. This is nice because usually when you want to show a link to the model, you have an instance of it, so in templates it's a matter of {{ species.get_absolute_url }}, for the linkify argument to django-tables2 columns, you mostly can get away with linkify=True.

You are right about the docs on linkify, they certainly need improvement.

Upvotes: 7

Related Questions