Django CMS - check if placeholder is empty
Asked Answered
P

7

11

I use:

  • DjangoCMS 2.4
  • Django 1.5.1
  • Python 2.7.3

I would like to check if my placeholder is empty.

<div>
    {% placeholder "my_placeholder" or %}
    {% endplaceholder %}
</div>

I don't want the html between the placeholder to be created if the placeholder is empty.

{% if placeholder "my_placeholder" %}
<div>
    {% placeholder "my_placeholder" or %}
    {% endplaceholder %}
</div>
{% endif %}
Pahari answered 17/6, 2013 at 12:40 Comment(0)
A
18

There is no built-in way to do this at the moment in django-cms, so you have to write a custom template tag. There are some old discussions about this on the django-cms Google Group:

Based on the code in the first discussion, I've put together the following Gist:

I use it like so:

{% load extra_cms_tags %}
{% get_placeholder "My Placeholder" as my_placeholder %}

{% if my_placeholder %}
<div>
    {{ my_placeholder }}
</div>
{% endif %}
Anthonyanthophore answered 17/6, 2013 at 13:2 Comment(4)
I'm a beginner. Where should have put the file ?Pahari
It's a template tag so you have to create a folder called templatetags in one of your applications, create a file (extra_cms_tags.py for example) then in your template call {% load extra_cms_tags %} to import itKneehigh
Don't forget to add __init__.py to your templatetags folder ;). See custom template-tags documentation for more details.Germiston
If you keep scrolling there's a better answer: https://mcmap.net/q/958717/-django-cms-check-if-placeholder-is-emptyCompress
P
6

If you want additional content to be displayed in case the placeholder is empty, use the or argument and an additional {% endplaceholder %} closing tag. Everything between {% placeholder "..." or %} and {% endplaceholder %} is rendered in the event that the placeholder has no plugins or the plugins do not generate any output.

Example:

{% placeholder "content" or %}

There is no content.

{% endplaceholder %}
Pourparler answered 19/3, 2016 at 5:43 Comment(3)
This should be the correct answer. Super simple and does not require template tags.Hanan
This is great, but it doesn't let you output HTML content only if the placeholder is not empty.Parsimonious
@Parsimonious I'm not sure in which version did you try and it didn't do that, but on django-cms==3.4.6 it works like a charm: the content between the tags appears ONLY if the placeholder is empty.Compress
S
5

Here's a very compact solution.

Template filter:

@register.filter('placeholder_is_empty')
def placeholder_is_empty(request, slot):
    page = request.current_page
    placeholder = page.placeholders.get(slot=slot)
    return placeholder.cmsplugin_set.exists()

Usage in template:

{% if request|placeholder_is_empty:'myplaceholder' %}
    <h1>Here comes some content... </h1>
{% endif %}
Strouse answered 17/11, 2015 at 21:34 Comment(5)
Why not return placeholder.cmsplugin_set.exists()?Grass
Is this still needed in 2019, or are there better tools nowadays? it still works, but wonder if there is a "builtin" way?Christianna
Yes, @jabez, exists() is better. I've edited my answer.Strouse
Trying to implement this feature myself, where would I put the Template filter file?Auvil
@jmona789, this is explained very well here: docs.djangoproject.com/en/2.2/howto/custom-template-tagsStrouse
O
3

Depending on what you are trying to achieve, you can simply use CSS to hide the element if doesn't have content using the :empty selector. And if you are worried about white spaces you can use Django's in-build {% spaceless %} template tag to remove them.

So you'd get this template:

{% spaceless %}
<div class="hide_if_empty">
    {% placeholder "my_placeholder" %}
</div>
{% endspaceless %}

And this CSS:

hide_if_empty:empty {
    display: none;
}

Not exactly what was asked for as it doesn't remove the HTML - but this will solve the most common case where one wants to check if a place holder is empty, and doesn't require the introduction of a new template tag.

Often answered 22/7, 2016 at 14:10 Comment(0)
M
2

2023 update

Accepted answer https://mcmap.net/q/958717/-django-cms-check-if-placeholder-is-empty has issues with latest DjangoCMS.

Updated solution (credits for F.B. from DjangoCMS community).

Tested with Django CMS 4.

{% load get_placeholder %}
...
{% get_placeholder "content" as placeholder_content %}
{% if placeholder_content %}
    <div class="my-2">{{ placeholder_content }}</div>
{% endif %}

code of the templatetag .../templatetags/get_placeholder.py

from classytags.arguments import Argument, MultiValueArgument
from classytags.values import StringValue
from django import template
from django.utils.safestring import mark_safe

from cms.models.placeholdermodel import Placeholder as PlaceholderModel
from cms.templatetags.cms_tags import (
    DeclaredPlaceholder,
    Placeholder,
    PlaceholderOptions,
)

register = template.Library()


class RenderGetPlaceholder(Placeholder):
    """
    Render the content of a placeholder to a variable. Can be provided
    with the name of the placholder (i.e. "Header" in the case of a normal
    CMS page) or a template variable containing a placeholder (i.e. myentry.content in the
    case of an external app using a placeholder)

    {% get_placeholder ["string"|placeholder_var] as variable_name %}

    e.g.
    {% load extra_cms_tags %}
    {% get_placeholder "My Placeholder" as my_placeholder %}

    {% if my_placeholder %}
    <div>
        {{ my_placeholder }}
    </div>
    {% endif %}
    """

    name = "get_placeholder"

    options = PlaceholderOptions(
        Argument("name", resolve=True),
        MultiValueArgument("extra_bits", required=False, resolve=False),
        "as",
        Argument("varname", resolve=False, required=True),
        blocks=[
            ("endplaceholder", "nodelist"),
        ],
    )

    def render_tag(self, context, name, extra_bits, varname, nodelist=None):
        if isinstance(name, PlaceholderModel):
            content = name.render(context, None)
        else:
            content = super(RenderGetPlaceholder, self).render_tag(context, name, extra_bits, nodelist)
        context[varname] = mark_safe(content)
        return ""

    def get_declaration(self):
        # Fix some template voodoo causing errors
        slot = self.kwargs["name"].var.var.__str__().strip('"').strip("'")

        return DeclaredPlaceholder(slot=slot, inherit=False)


register.tag(RenderGetPlaceholder)
Mellicent answered 2/10, 2023 at 15:43 Comment(0)
C
1

Based on the great answer form @Philip Zedler, a solution that works for both placeholder on django-cms pages, but also on placeholders "outside of the cms".

@register.filter()
def placeholder_empty(page_placeholder, slot=None):
    """
    for page/slot, pass a page object, and a slot name:  
    {% if request.current_page|djangocms_misc_placeholder_empty:"content" %}

    for a outside page placeholder, just the placeholder object:
    {% if object.placeholderfield|djangocms_misc_placeholder_empty %}

    also, with:
    {% with ph_empty=object.placeholderfield|djangocms_misc_placeholder_empty %}
    """
    placeholder = None
    if isinstance(page_placeholder, Placeholder):
        placeholder = page_placeholder
    elif isinstance(page_placeholder, Page):
        page = page_placeholder
        try:
            placeholder = page.placeholders.get(slot=slot)
        except Placeholder.DoesNotExist:
            pass
    if placeholder:
        # // return not placeholder.cmsplugin_set.filter(language=get_language()).exists()
        return not placeholder.cmsplugin_set.exists()
    return False

usage in template

{% if request.current_page|placeholder_empty:'content' %}
    <h1>Fallback!</h1>
{% endif %}

It's in my djangocms-misc package

Christianna answered 30/1, 2020 at 14:26 Comment(0)
I
1

I took the extra compact solution here and created a templatetag that checks if a static placeholder is not empty:

from cms.toolbar.utils import get_toolbar_from_request

@register.filter("static_placeholder_is_not_empty")
def static_placeholder_is_not_empty(request, slot):

    placeholder = StaticPlaceholder.objects.get(code=slot)

    if get_toolbar_from_request(request).edit_mode_active:
        placeholder = placeholder.draft
    else:
        placeholder = placeholder.public

    is_not_empty = len(placeholder.get_plugins(request.LANGUAGE_CODE)) > 0
    return is_not_empty

It's used like this:

{% load my_new_shiny_templatetag %}

{% if request|static_placeholder_is_not_empty:'my_static_placeholder' %}
  <div class="something">
    {% static_placeholder "my_static_placeholder" %}
  </div>
{% endif %}

Edit: extra compact solution with current language support:

@register.filter("placeholder_is_empty")
def placeholder_is_empty(request, slot):
    page = request.current_page
    placeholder = page.placeholders.get(slot=slot)
    return not placeholder.cmsplugin_set.filter(language=request.LANGUAGE_CODE).exists()
Insufficient answered 12/4, 2022 at 15:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.