Add iommi to a FBV#

Let’s say we have a simple view to display an album:

def view_artist(request, artist_name):
    artist = get_object_or_404(Artist, name=artist_name)
    return render(
        request,
        'view_artist.html',
        context={
            'artist': artist,
        },
    )
▼ Hide result

There’s a table in the template for the tracks but it’s all manual written <table>, <tr>, etc tags and so doesn’t have sorting, and it’s just a lot of code in that template. It would be nicer to use an iommi table!

Add an iommi table#

def view_artist(request, artist_name):
    artist = get_object_or_404(Artist, name=artist_name)

    albums = Table(
        auto__rows=artist.albums.all(),
    ).bind(request=request)

    return render(
        request,
        'view_artist2.html',
        context={
            'artist': artist,
            'albums': albums,
        }
    )
▼ Hide result

Now in the template we can add {{ albums }} to render the table, and we can delete all the old manually written table html.

AJAX dispatch#

There are two problems with this code so far though, and that is that if we add filtering on album it breaks. One of the nice features of iommi is the automatic ajax endpoints (and by default a select2 widget), but this requires some extra routing, and that we include the relevant JS assets.

For views that are fully iommi the routing is done for you, but as this is a legacy function based view that we don’t want to rewrite fully right now, we’ll have to add the routing boilerplate ourselves:

def view_artist(request, artist_name):
    artist = get_object_or_404(Artist, name=artist_name)

    tracks = Table(
        auto__rows=Track.objects.filter(album__artist=artist),
        columns__album__filter__include=True,
    ).bind(request=request)

    dispatch = tracks.perform_dispatch()
    if dispatch is not None:
        return dispatch

    return render(
        request,
        'view_artist.html',
        context={
            'artist': artist,
            'tracks': tracks,
            'assets': tracks.iommi_collected_assets(),
        }
    )

You will also have to render the assets into the <head> block of your html:

{% for asset in assets.values %}
    {{ asset }}
{% endfor %}

Multiple iommi components#

You should only create one iommi component in order to get the automatic namespacing for free. So if you wanted to add two tables, you should wrap them in a Page:

def view_artist(request, artist_name):
    artist = get_object_or_404(Artist, name=artist_name)

    class MyPage(Page):
        albums = Table(auto__rows=artist.albums.all())
        tracks = Table(
            auto__rows=Track.objects.filter(album__artist=artist),
            columns__album__filter__include=True,
        )
    page = MyPage().bind(request=request)

    dispatch = page.perform_dispatch()
    if dispatch is not None:
        return dispatch

    return render(
        request,
        'view_artist3.html',
        context={
            'artist': artist,
            'tracks': page.parts.tracks,
            'albums': page.parts.albums,
        }
    )
▼ Hide result