Merengue: The new surprising and refreshing Django based CMS.

EuroPython 2011

Background

Built by Plone experienced people who love the Django framework

Experience with Plone CMS:

Plone is very good at first glance:

But... Too complex and difficult to extend

Django came... was great

But... is not a CMS

(no conventions, no prepared glue)

CMS development with Django means...

doing repetitive tasks

And the Malaga University came...

Philosophy

Merengue principles

But also easy to install and use

Features

Cool features

Other features 1/3

Other features 2/3

Other features 3/3

Some plugins 1/2

Some plugins 2/2

Applications used

Applications used (1/3)

Applications used (2/3)

Applications used (3/3)

Show me the code

Content types

Extending data model

from merengue.base.models import BaseContent

class Author(BaseContent):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)

class Book(BaseContent):
    authors = models.ManyToManyField(Author)

Themes

Template snippet

themes/footheme/inc.languagetools.html

{% extends "base/inc.languagetools.html" %}

{% load i18n %}

{% block languageitem %}
 <img alt="{% trans 'Change language' %} {{ lang_name }}"
      title="{% trans 'Change language' %} {{ lang_name }}"
      src="{{ THEME_MEDIA_URL }}img/flag-{{ lang }}.gif" />
{% endblock %}

Actions

Action code example

from merengue.action.actions import UserAction
from merengue.base.utils import get_login_url

class LoginAction(UserAction):
    name = 'loginaction'
    verbose_name = _('Login')

    def has_action(self, request, user):
        return not user.is_authenticated()

    def get_url(self, request, user):
        return get_login_url()

Blocks

Block code example

from merengue.block.blocks import Block
from plugins.news.views import get_news

class LatestNewsBlock(Block):
    name = 'latestnews'
    default_place = 'leftsidebar'

    def render(self, request, place, context):
        news_list = get_news(request, 5)
        return self.render_block(
            request, template_name='news/block_latest.html',
            block_title='Latest news',
            context={'news_list': news_list})

Admin stuff

Admin fragment example

from merengue.base.admin import RelatedModelAdmin

class ContactInfoRelatedAdmin(RelatedModelAdmin):
    """ Contact info related to a content """
    tool_name = 'contact_info'
    tool_label = _('contact info')
    one_to_one = True
    related_field = 'basecontent'

def register(site):
    site.register_related(BaseContent,
                          ContactInfoRelatedAdmin,
                          related_to=BaseContent)

Plugins

Plugin example 1/2

from merengue.pluggable import Plugin

from plugins.event.admin import EventAdmin, EventCategoryAdmin,
                                EventSectionAdmin
from plugins.event.blocks import EventsCalendarBlock
from plugins.event.models import Event, Category

class PluginConfig(Plugin):
    name = 'Events'
    description = 'Events plugin'
    version = '0.0.1a'
    url_prefixes = (
        ({'en': 'event',
          'es': 'eventos'},
          'plugins.event.urls'),
    )
    ... # more stuff

Plugin example 2/2

class PluginConfig(Plugin):
    name = 'Events'
    ... # more stuff

    def models(self):
        return [
            (Event, EventAdmin),
            (Category, EventCategoryAdmin),
        ]

    def section_models(self):
        return [(Event, EventSectionAdmin)]

    def get_blocks(self):
        return [EventsCalendarBlock]

Creating a plugin demo

To learn more

Go to docs.merengueproject.org

Can I help?

Contributing

Thanks!

Visit: www.merengueproject.org

Slides: www.merengueproject.org/europython_2011/slides.html

Contact: msaelices@yaco.es/@linator