Merengue: The new surprising and refreshing Django based CMS.
Merengue: The new surprising and refreshing Django based CMS.
EuroPython 2011
Built by Plone experienced people who love the Django framework
Experience with Plone CMS:
- From 2003
- Several projects
- Let us grow
Plone is very good at first glance:
- Very usable
- Full featured
- Internationalized
But... Too complex and difficult to extend
Django came... was great
- Very elegant code
- Pragmatic philosophy
- Fast developing
- Large etcetera...
But... is not a CMS
(no conventions, no prepared glue)
CMS development with Django means...
doing repetitive tasks
- Layout and look&feel from scratch
- Make Django apps work together
- Hack admin or create new one
- Etcetera
And the Malaga University came...
- Sponsored us to build a CMS
- 4500+ working hours
- From a pragmatic point of view
- Learning from Plone experience
Merengue principles
- Focus on programmers
- Flexible
- Easy to learn
- Easy to extend
But also easy to install and use
Cool features
- Block management
- Translation tools
- Inline editing
- More flexible admin interface
- Cool pluggable architecture
- A flexible Theming system
- A lot of optimizations
Other features 1/3
- Content management
- Pluggable
- Permissions
- Workflows
- i18n and l10n
- Documentation
- WYSIWYG editors
Other features 2/3
- Search
- Tags
- Comments
- Captcha
- Internationalized URLs
- Review system
- Federated AuthN/AuthR via SAML
Other features 3/3
- SEO
- RSS
- GIS
- Tests
- A lot of plugins
- And all the Django 1.3 features
- Also... Italian translation :)
Some plugins 1/2
- Feedback
- RSS
- Forum
- Event
- News
- Voting
- Maps
- MicroSites
Some plugins 2/2
- Standing out
- Contact form
- Smart search
- AddThis.com
- Internationalized Tags
- Twitter
- Open Office export
Applications used (1/3)
- django-transmeta
- django-inlinetrans
- django-inplaceedit
- django-autoreports
- django-configfield
- django-oot
- johnny-cache
- south
Applications used (2/3)
- django-tagging
- django-oembed
- django-threadedcomments
- django-pagination
- django-ajax-selects
- django-compressor
- django-classy-tags
- django-announcements
Applications used (3/3)
- django-genericforeignkey
- django-stdfile
- cmsutils
- transhette
- sorl-thumbnail
- searchform
- django-form-admin
Content types
- Managed content is BaseContent
- Can be extended
- Workflowable
- Have permissions
- And a lot of features
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
- Implemented as template loader
- Active theme stored in database
- Very flexible
- With place holder templates
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
- Actions are actions
- Are categorized
- Logic to show them or not
- Login, PDF export, RSS, etc.
- Defined in plugins
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
- Render a page fragment
- Are also categorized
- Located (header, left, etc.)
- Defined in plugins
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
- Related admins
- Many new widgets
- Admin sites loaded dinamically
- Autocompletion
- Sorting by drag-and-drop
- Translation tool
Admin fragment example
from merengue.base.admin import RelatedModelAdmin
class ContactInfoRelatedAdmin(RelatedModelAdmin):
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
- It's a place holder
- Can define blocks, actions, middlewares, models, panels, permissions, viewlets, etc.
- Can be configured with dynamic parameters
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'),
)
...
Plugin example 2/2
class PluginConfig(Plugin):
name = 'Events'
...
def models(self):
return [
(Event, EventAdmin),
(Category, EventCategoryAdmin),
]
def section_models(self):
return [(Event, EventSectionAdmin)]
def get_blocks(self):
return [EventsCalendarBlock]
To learn more
- Testing
- Theming
- Collections
- Viewlets
- etc.
Contributing
- Any help will be appreciated
- Like Django does...
- dev.merengueproject.org
- merengue-developers Google group
- Sprint at EuroPython