Search code examples
djangodjango-tables2

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.


Solution

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