eudicots / Cactus

Static site generator for designers. Uses Python and Django templates.
BSD 3-Clause "New" or "Revised" License
3.47k stars 314 forks source link

custom django templatetags libraries #31

Open amitu opened 11 years ago

amitu commented 11 years ago

Once # 30 is merged, the following diff implements this feature.

diff --git a/cactus/models.py b/cactus/models.py
new file mode 100644
index 0000000..e69de29
diff --git a/cactus/site.py b/cactus/site.py
index 0650d8f..f6e1f35 100644
--- a/cactus/site.py
+++ b/cactus/site.py
@@ -61,7 +61,9 @@ class Site(object):
                        logging.exception("Caught exception while opening config file")
                        config = {}

-               config.setdefault("INSTALLED_APPS", []).append("django.contrib.markup")
+               config.setdefault("INSTALLED_APPS", []).extends(
+                       ["django.contrib.markup", "cactus"]
+               )
                config.setdefault("TEMPLATE_DIRS", []).extend(
                        [self.paths['templates'], self.paths['pages']],
                )
@@ -358,6 +360,7 @@ class Site(object):
                        # Set an id based on the file name
                        plugin.id = pluginHandle

+                       sys.modules["cactus.templatetags.%s" % pluginHandle] = plugin
                        plugins.append(plugin)

                # Sort the plugins by their defined order (optional)
diff --git a/cactus/templatetags/__init__.py b/cactus/templatetags/__init__.py
new file mode 100644
index 0000000..e69de29

It is a bit hacky, I am making cactus project itself a valid django app by adding cactus.models module and cactus.templatetags package. Then I am putting all plugins available as cactus.templatestags.PLUGIN_NAME, Sample plugin, plugins/t.py:

from django import template
import random

register = template.Library()

@register.filter
def randomize(value):
    return "".join(random.sample(value, len(value)))

To use it in template:

{% extends "base.html" %}
{% load t %}
{% block content %}
    {{ "Welcome to Cactus!"|randomize }}
{% endblock %}

I thought of some naming convention for plugins, so only some plugins are added to cactus.templatetags.PLUGIN_NAME, but rejected it as now I can ship a blog plugin that contains both plugin hooks and custom templatetag libraries all related to blogging, list of posts etc.

rukeba commented 11 years ago

+1

stepmr commented 11 years ago

+1

moskrc commented 10 years ago

+1

WillsB3 commented 9 years ago

Can anyone tell me what the status is here? I'd like to know if (and how) to create and use custom Django template tags with Cactus?

Thanks.

krallin commented 9 years ago

You can actually do this today (at least in v3, which is now the master version) using a plugin.

Here's an example:

from django import template
from django.template.loader import get_template

def signup_button(context, location):
    """
    Display the signup button
    """
    ctx = copy.copy(context)
    ctx.update({"loc": location})
    return ctx

def preBuild(_):
    register = template.Library()
    register.inclusion_tag(get_template('includes/buttons/signup-button.html'), takes_context=True)(signup_button)
    template.base.builtins.append(register)

Note that it's probably possible to clean this up a bit (and not hack into builtins). Looking at how Django loads new templatetags files is probably the best way to find out.

I seem to recall I had injected into builtins to not have to re-load this tag which was going to be used on every single page of my website, but I'm sure there's a cleaner way.

WillsB3 commented 9 years ago

Thanks @krallin - I'll give that a go :+1:

krallin commented 9 years ago

Let me know if you run into any trouble. It's been a while since I used that plugin, but I'm pretty sure that site used to build so there has to be a way to make it work! : )

pmdarrow commented 9 years ago

@krallin the snippet you posted doesn't seem to work. I tried it with a really simple filter:

from django import template

def mymarkdown(value):
    return 'test'

def preBuild(site):
    register = template.Library()
    register.filter('mymarkdown', mymarkdown)

Which gives me:

django.template.base.TemplateSyntaxError: Invalid filter: 'mymarkdown'
pmdarrow commented 9 years ago

Update: the following works

from cactus.template_tags import register

def mymarkdown(value):
    return 'test'

def preBuild(site):
    register.filter('mymarkdown', mymarkdown)
krallin commented 9 years ago

@pmdarrow ,

You might have missed that line from the snippet:

template.base.builtins.append(register)

If you don't add that line, then you'd have to {% load ... %} the library.

Cheers,

pmdarrow commented 9 years ago

@krallin I'm writing a custom filter, and I registered it with Cactus' library using

from cactus.template_tags import register
register.filter('mymarkdown', mymarkdown)

so no builtins hacking was required.

krallin commented 9 years ago

@pmdarrow ,

I understand that. I was simply explaining why the snippet I provided did not work for you.

Basically, there are two ways to add a filter:

Note that the cactus.template_tags library is added to the Django built-ins for you by Cactus:

https://github.com/koenbok/Cactus/blob/2dd7159280363f0b762d43e3bfa1ec1a2a6effea/cactus/site.py#L156

So, there's still builtins hacking, only it's not your plugin doing it ;)

Now, obviously, both ways work equally well! : )

Cheers,

pmdarrow commented 9 years ago

@krallin ah, that makes sense :smiley:. It would be awesome if there was some docs for this, but I see that's on the roadmap in #117. Might be worth closing this issue now that there's a solution.