Reputation: 8659
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
Reputation: 1023
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
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
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
from django.urls import path
from . import views
urlpatterns = [
path('<int:id>', views.detail, name="example-view-name"),
]
# 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
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