Using django-cms, how can I allow the user to specify a background image
Asked Answered
S

3

5

I am creating a django-cms site for a client. I would like to do something like:

<body style="background-image:url({% placeholder background-image %});">

The desired effect is to have a place where the user of the CMS can select a background image for a page. Ideally, they would choose an existing picture using something like Filer.

Is there a way to do this?

Stevestevedore answered 19/7, 2013 at 19:46 Comment(0)
A
3

Paulo is right, the first step is to configure a placeholder so that it can only take at most one image plugin, in this case, FileImagePlugin. Do that by modifying CMS_PLACEHOLDER_CONF:

CMS_PLACEHOLDER_CONF = {
    'cover_image': {
        'plugins': ['FilerImagePlugin'],
        'name': _('Cover Image'),
        'limits': {'global': 1},
    },
}

Make sure in your template, you are showing this placeholder somewhere:

{% load cms_tags %}
{% placeholder "cover_image" %}

This will render the image in an <img> tag. But what if you want just the URL of the image? That's what the second step is.

Create a context processor that will give you the image directly. The details will modify depending on what image plugin you're using, but this is the one I used:

# in context_processors.py
from cms.models.pluginmodel import CMSPlugin

def page_extra(request):
    page = request.current_page
    if page:
        cover_image_plugin = CMSPlugin.objects.filter(
            placeholder__page=page,
            placeholder__slot='cover_image',
            plugin_type='FilerImagePlugin',
        ).first()
        if cover_image_plugin:
            return {'cover': cover_image_plugin.filerimage.image}
    return {}

Remember to install the context processor in your settings.py file:

TEMPLATES[0]['OPTIONS']['context_processors'].append('example.context_processors.page_extra')

Now in your template, you can access the URL using cover.url, like this:

<body
  {% if cover %}
    style="background-image: url('{{ cover.url|urlencode }}')"
  {% endif %}
>
Author answered 15/8, 2016 at 15:31 Comment(1)
Where should I place "{% placeholder "cover_image" %}" tag? "cover.url|urlencode" is empty for me.Berezina
S
2

Great answer Flimm, thanks!

I get an error, however, in the context processor saying that a CMSPlugin object does not have a filerimage attribute. Here's the context processor that works for me:

# in context_processors.py
from cms.models.pluginmodel import CMSPlugin

def cover_image(request):
    page = request.current_page
    if page:
        cover_image_plugin = CMSPlugin.objects.filter(
            placeholder__page=page,
            placeholder__slot='cover_image',
            plugin_type='FilerImagePlugin',
        ).first()
        if cover_image_plugin:
            return {'cover': cover_image_plugin.get_plugin_instance()[0]}
    return {}

Note the change in the but last line. get_plugin_instance retrieves the rightly subclassed instance object as the first entry of a tuple. (I use Django CMS 3.4)

As a last remark, the cover_image placeholder needs to be in a place that is not rendered.

Shogunate answered 28/9, 2016 at 15:20 Comment(2)
"As a last remark, the cover_image placeholder needs to be in a place that is not rendered." - where then it should be?Berezina
@DmitriyVinokurov E.g, by putting it inside <div style="displkay: none;"> ... </div>. This avoids double-rendering.Shogunate
C
0

You are on the right track, once that's there when all you need is the plugin which in this case you can use filer. And to make it better you can use the CMS_PLACEHOLDER_CONF setting to only allow that one plugin to be placeholder inside the background-image placeholder, like so:

CMS_PLACEHOLDER_CONF = {
    'background-image': {
        "plugins": ('YourImagePlugin', ),
        'name':"Background Image",
        'limits': {
            'global': 1,
        },
    },
}
Chari answered 21/7, 2013 at 18:56 Comment(2)
That's only half of the solution. The other half is how do you get just the image URL? {% placeholder backround-image %} will render an <img> tag, which is not what is needed here, just the URL.Author
I guess I misunderstood the question :). Instead of a plugin based approach, it's better to use a page extension for this.Chari

© 2022 - 2024 — McMap. All rights reserved.