Unresolved library error when trying to load custom tag in Wagtail CMS

Viewed 538

I am new to Wagtail but have some knowledge in Django. I was trying to follow the official documentation of Wagtail but I got stuck in the snippets section. I am trying to render a snippet NavigationComponent in home/templates/home/home_page.html. I have defined a tag in home\templatetags\navigation_tags.py to render it. However when I am trying to load the tag using {% load %}, it doesn't recognize it.

Here is the code:-

[base.py]

INSTALLED_APPS = [
    'home',
    'search',
    'website',
    'wagtail.contrib.forms',
    'wagtail.contrib.redirects',
    'wagtail.embeds',
    'wagtail.sites',
    'wagtail.users',
    'wagtail.snippets',
    'wagtail.documents',
    'wagtail.images',
    'wagtail.search',
    'wagtail.admin',
    'wagtail.core',
    'modelcluster',
    'taggit',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

###########################################################################################

[home/models.py]

from django.db import models

from wagtail.core.models import Page
from wagtail.snippets.models import register_snippet
from wagtail.admin.edit_handlers import FieldPanel, PageChooserPanel


class HomePage(Page):
    pass


@register_snippet
class NavigationComponent(models.Model):

    name = models.CharField(max_length=50, blank=False)
    link = models.ForeignKey(
        'wagtailcore.Page',
        null=True,
        blank=False,
        on_delete=models.SET_NULL,
        related_name='+'
    )
    url = models.URLField(blank=True, null=True)

    panels = [
        FieldPanel('name'),
        PageChooserPanel('link'),
        FieldPanel('url')
    ]

    def __str__(self):
        return self.name

    class Meta:
        verbose_name_plural = 'Navigation Item Container'
        verbose_name = "Navigation Item Container"


@register_snippet
class NavigationItem(models.Model):

    name = models.CharField(max_length=50, blank=False)
    link = models.URLField()

    class Meta:
        verbose_name_plural = 'Navigation Items'


[home/templatetags/navigation_tags.py]

from django import template
from ..models import NavigationComponent

register = template.Library()


@register.inclusion_tag('../templates/tags/navigation_component.html', takes_context=True)
def navigation_components(context):
    return {
        'components': NavigationComponent.objects.all(),
        'request': context['request']
    }

##########################################################################################

[home/templates/home/home_page.html]

{% extends "base.html" %}
{% load static navigation_tags %}                       # Unresolved library 'navigation_tags'

{% block body_class %}template-homepage{% endblock %}

{% block extra_css %}

<link rel="stylesheet" href="{% static 'css/welcome_page.css' %}">
{% endblock extra_css %}

{% block navigation %}
    {%  navigation_components %}                                       # template error :Invalid block tag
{% endblock %}

{% block content %}

{% endblock content %}



templatetags is a python package. I have looked through both Django and Wagtail documentation yet I can't figure out what I am doing wrong.

1 Answers

What about adding directly NavigationComponent queryset within context of HomePage model?

# models.py

class HomePage(Page):
    ...

    def get_context(self, request):
        context = super().get_context(request)
        context['components'] = NavigationComponent.objects.all()
        return context

then you can access queryset components within home_page.html template

<!-- home_page.html -->

...

{% for item in components %}
    <a href="{{ item.name }}">{{ item.name }}</a>
{% endfor %}

...

UPDATE

Step 1

navigation_tags.py seems to be correct, I would drop context here as it does not seem to be useful

# home/templatetags/navigation_tags.py

@register.inclusion_tag('tags/navigation_component.html')
def navigation_components():
    return {'components': NavigationComponent.objects.all()}

Step 2

Create the template navigation_component.html, put here what you want to have when you will call you tag within another template with {% navigation_components %}

<!--home/templates/tags/navigation_component.html-->

{% for e in components %}
    <a href="{{ e.url }}">{{ e.name }}</a>
{% endfor %}

Step 3

<!-- home/templates/home/home_page.html -->

{% load static navigation_tags %}

...

{% navigation_components %}  <!-- Call of your tag -->

...

Be careful of every file-paths and Good luck!

Related