Django cms best practices

Preview:

Citation preview

DJANGO MEETUP - SKILLS MATTER

DJANGO CMSBEST PRACTICES

by

Iacopo Spalletti

@yakkys

WHO AM I?Founder and Lead developer @NephilaIt

django CMS core developer 

django CMS installer author

DJANGO CMS

BEST PRACTICESdjango CMS applications are just Django applications

With a twist

DJANGO CMS BEST PRACTICES

WHY?Writing Django applications is easy

Writing effective and clean Django applications

requires some effort

DJANGO CMS BEST PRACTICES

WHAT'S THAT?Guidelines being developed by the core team

Community feedback

My experience

DJANGO CMS BEST PRACTICES

WHAT FOR?Providing:

DRY

Reusability

Tight integration with on-site and off-site services (full-

text search, social networks ...)

Principle of least surprise

DJANGO CMS BEST PRACTICES

CAVEATSNowhere near comprehensive

Still in flux

Task for 2015: Define the best practices Code hooks

into django CMS core

DJANGO CMS BEST PRACTICES

YET ANOTHER BLOGEXAMPLE

Standard blog features

Pluggable onto multiple pages with different

configurations

Integration with social networks

Integration with full-text search

DJANGO CMS BEST PRACTICES

THE BASICSalways define cms_app.py

never plug the application in urlconf directly

prefer translatable models using django-parler

use tests :)

follow code conventions

(don't follow this talk code style)

DJANGO CMS BEST PRACTICES

THE DETAILSTemplates inheritance

Namespace configuration

django CMS Frontend editor

django CMS Toolbar

Meta tags

Haystack integration

DJANGO CMS BEST PRACTICES

LET'S STARTWe will use djangocms_blog as a base

List of posts

Post detail view

Tags

Categories

Comments

...

DJANGO CMS BEST PRACTICES

TEMPLATES INHERITANCEUse django CMS page templates!

{% extends CMS_TEMPLATE %}

{% block meta %}    {%  if meta %}        {% include "meta_mixin/meta.html" %}    {% endif %}{% endblock meta %}

{% block content %}<div class="app app­blog span8">    {% block content_blog %}{% endblock %}</div>{% endblock content %}

DJANGO CMS BEST PRACTICES

TEMPLATE RULESExtends CMS_TEMPLATE variable

Define a conventional block each applicationshould redefine

We'll see the meta_mixin/meta.html include

later

DJANGO CMS BEST PRACTICES

TEMPLATES LAYOUTDivide application template from plugin ones

DJANGO CMS BEST PRACTICES

TEMPLATES LAYOUTUse includes to share the common code

<div class="plugin plugin­blog"><div class="blog­latest­entries">    {% for post in posts_list %}        {% include "djangocms_blog/includes/blog_item.html" with post=post TRUNCWORDS_COUNT=TRUNCWORDS_COUNT %}    {% empty %}        <p class="blog­empty">{% trans "No article found." %}</p>    {% endfor %}    </div></div>

DJANGO CMS BEST PRACTICES

NAMESPACE SUPPORTDjango built in support:

from django.conf.urls import include, patterns, url

urlpatterns = patterns('',    url(r'̂blog/', include('djangocms_blog.urls', namespace='blog1'    url(r'̂other­blog/', include('djangocms_blog.urls', namespace='blog2')

my_url = reverse('djangocms_blog:index', current_app='blog1')my_url = reverse('djangocms_blog:index', current_app=request.resolver_match.namespace)

DJANGO CMS BEST PRACTICES

DJANGO CMS SUPPORTdjango CMS just uses Django's own

class BlogApp(CMSApp):    name = _('Blog')    urls = ['djangocms_blog.urls']    app_name = 'djangocms_blog'

apphook_pool.register(BlogApp)

DJANGO CMS BEST PRACTICES

NEW IN 3.1!Enter aldryn-apphooks-config

class BlogConfig(TranslatableModel, AppHookConfig):    paginate_by = models.PositiveIntegerField(        _('Paginate size'),        blank=False,        default=5,    )    ...

class NewsBlogConfigForm(AppDataForm):    passsetup_config(NewsBlogConfigForm, NewsBlogConfig)

DJANGO CMS BEST PRACTICES

ALDRYN-APPHOOKS-CONFIG

Integrated with django CMS namespace instancecreation

Definition of per-namespace instance options

Tied to each model instanceclass Post(ModelMeta, TranslatableModel):   ...   app_config = models.ForeignKey(BlogConfig,        verbose_name=_('app. config'))

DJANGO CMS BEST PRACTICES

IN VIEWSAppConfigMixin:

sets up the namespace support

retrieves the current configuration

class PostListView(AppConfigMixin, ViewUrlMixin, ListView):    model = Post    context_object_name = 'post_list'    template_name = 'djangocms_blog/post_list.html'    view_url_name = 'djangocms_blog:posts­latest'

    def get_paginate_by(self, queryset):        return self.app_config.paginate_by

DJANGO CMS BEST PRACTICES

IN THE ADMINUse ModelAppHookConfig to get options values

(e.g. in admin forms)

class PostAdmin(EnhancedModelAdminMixin, FrontendEditableAdminMixin                PlaceholderAdminMixin, TranslatableAdmin, ModelAppHookConfig                admin.ModelAdmin):

    app_config_values = {        'default_published': 'publish'    }

DJANGO CMS BEST PRACTICES

IN THE TEMPLATEAccess the related namespace instance config through

the current model

{% if post.app_config.use_placeholder %}    <div class="blog­content">{% render_placeholder post.content %}{% else %}    <div class="blog­content">{% render_model post "post_text" "post_text" %}{% endif %}

DJANGO CMS BEST PRACTICES

DJANGO CMS FRONTENDEDITOR

DJANGO CMS BEST PRACTICES

DJANGO CMS FRONTENDEDITOR

Base for plugins behaviour

A wrapper around standard Django admin

Available for all Django applications

DJANGO CMS BEST PRACTICES

USE IT!Add FrontendEditableAdminMixin

class PostAdmin(FrontendEditableAdminMixin,                PlaceholderAdminMixin, TranslatableAdmin,                admin.ModelAdmin):    model = Post    frontend_editable_fields = ('title', 'abstract', 'post_text')    ...

DJANGO CMS BEST PRACTICES

USE IT!Add template magic

<h2>{% render_model post "title" %}</h2>

<div class="blog­content">{% render_model post "post_text" "post_text" %}</div>

Edit the whole post

Or just some fields

DJANGO CMS BEST PRACTICES

USE IT!

DJANGO CMS BEST PRACTICES

POWER TO THE USERSToolbar is the main django CMS UI

DJANGO CMS BEST PRACTICES

POWER TO THE USERSAvailable to all Django applications

DJANGO CMS BEST PRACTICES

HOW TO IMPLEMENT ITToolbar is very rich and powerful

I'll just show the basics

Check documentation for detailshttp://django-cms.rtfd.org/en/develop/how_to/toolbar.html

DJANGO CMS BEST PRACTICES

HOW TO IMPLEMENT ITCreate cms_toolbar.pyDefine the links to the admin views

@toolbar_pool.registerclass BlogToolbar(CMSToolbar):    watch_models = [Post]

    def populate(self):        if not self.is_current_app:            return        admin_menu = self.toolbar.get_or_create_menu(             'djangocms_blog', _('Blog'))        url = reverse('admin:djangocms_blog_post_changelist')        admin_menu.add_modal_item(_('Post list'), url=url)        url = reverse('admin:djangocms_blog_post_add')        admin_menu.add_modal_item(_('Add post'), url=url)

 

DJANGO CMS BEST PRACTICES

HOW TO IMPLEMENT ITAdd contextual-aware links

current_post = getattr(self.request, BLOG_CURRENT_POST_IDENTIFIER)if current_post:    admin_menu.add_modal_item(_('Edit Post'),        reverse(            'admin:djangocms_blog_post_change',                args=(current_post.pk,)        ), active=True)

class PostDetailView(TranslatableSlugMixin, BaseBlogView, DetailView)    model = Post    def get_context_data(self, **kwargs):        context = super(PostDetailView, self).get_context_data(**kwargs)        setattr(self.request, BLOG_CURRENT_POST_IDENTIFIER, self.get_object())        return context

DJANGO CMS BEST PRACTICES

SOME NOTESRedirect browser to current post upon edit

class BlogToolbar(CMSToolbar):    watch_models = [Post]

Hide the application toolbar item when outside the

application URLs

def populate(self):    if not self.is_current_app:        return

DJANGO CMS BEST PRACTICES

SHARE THE PASSION!Content is dumb without metadata

schema.org

OpenGraph

...

Metadata defines the meaning of the content

DJANGO CMS BEST PRACTICES

DJANGO CMS HAS GOTTHAT COVERED!

django-meta / django-meta-mixin

Django applications to format document metadata:

title

author

image

...

DJANGO CMS BEST PRACTICES

AN EXAMPLEDefine an attribute that maps metadata properties to

attribute/function/callable

Include a template

...

That's all

 

DJANGO CMS BEST PRACTICES

THE MODEL_metadata = {    'title': 'get_title',    'description': 'get_description',    'og_description': 'get_description',    'image': 'get_image_full_url',    'object_type': get_setting('TYPE'),    ....}

def get_title(self):    title = self.safe_translation_getter('meta_title')    if not title:        title = self.safe_translation_getter('title')    return title.strip()

def get_image_full_url(self):

DJANGO CMS BEST PRACTICES

THE VIEWas_meta() method does the magic

def get_context_data(self, **kwargs):    context = super(MyView, self).get_context_data(**kwargs)    context['meta'] = self.get_object().as_meta()    return context

DJANGO CMS BEST PRACTICES

THE TEMPLATETemplates are even easier

<head>    ...    {% include "meta_mixin/meta.html" %}    ...</head>

DJANGO CMS BEST PRACTICES

IT'S DONE<meta property="og:title" content="L'evento Djangobeer a Firenze, organizzato da Nephila"<meta property="og:url" content="http://www.nephila.it/it/blog/2014/09/18/djangobeer/"<meta property="og:description" content="La prima Djangobeer a Firenze: com'è nata l'idea, come si è svolta la serata e lo sviluppo di un evento, a partire dal logo. Un evento in cui la cultura della birra si unisce a quella dell'Open Source."<meta property="og:image" content="http://www.nephila.it/media/filer_public/76/1e/761ed2d2­cd6e­41db­ab72­e2e0c613f903/djangobeer.jpg"<meta property="og:type" content="Article"><meta property="article:published_time" content="2014­09­18 18:03:20"<meta property="article:modified_time" content="2014­12­24 11:44:15.769410"<meta name="twitter:domain" content="www.nephila.it"><meta name="twitter:card" content="Summary"><meta name="twitter:title" content="L'evento Djangobeer a Firenze, organizzato da Nephila"<meta name="twitter:url" content="http://www.nephila.it/it/blog/2014/09/18/djangobeer/"<meta name="twitter:description" content="La prima Djangobeer a Firenze: com'è nata l'idea, come si è svolta la serata e lo sviluppo di un evento, a partire dal logo. Un evento in cui la cultura della birra si unisce a quella dell'Open Source."<meta name="twitter:image:src" content="http://www.nephila.it/media/filer_public/76/1e/761ed2d2­cd6e­41db­ab72­e2e0c613f903/djangobeer.jpg"<meta name="twitter:creator" content="@NephilaIt"><meta name="twitter:site" content="@nephilait"><link rel="author" href="https://plus.google.com/+NephilaIt"/>

DJANGO CMS BEST PRACTICES

THE IMPORTANCE OF BEINGINDEXED

What if I want to make my content indexable?

aldryn_search to the rescue

Easier binding between Haystack and your models

Knows a few things of django CMS

DJANGO CMS BEST PRACTICES

HOW TO CREATE THE INDEXsearch_indexes.py

class PostIndex(get_index_base()):    def get_title(self, obj):        return obj.get_title()

    def index_queryset(self, using=None):        self._get_backend(using)        language = self.get_current_language(using)        filter_kwargs = self.get_index_kwargs(language)        qs = self.get_index_queryset(language)        if filter_kwargs:            return qs.translated(language, **filter_kwargs)        return qs

    def get_index_queryset(self, language):        return self.get_model().objects.active_translations(            language_code=language).filter(app_config__search_indexed=

DJANGO CMS BEST PRACTICES

HOW TO CREATE THE INDEX#2

def get_search_data(self, language=None, request=None):        """        Provides an index for use with Haystack, or, for populating        Article.translations.search_data.        """        if not self.pk:            return ''        if language is None:            language = get_language()        if request is None:            request = get_request(language=language)        description = self.safe_translation_getter('lead_in')        text_bits = [strip_tags(description)]        for category in self.categories.all():            text_bits.append(                force_unicode(category.safe_translation_getter('name'

DJANGO CMS BEST PRACTICES

CONFUSED?It may looks complex at first

Have a look at other examples

aldryn-newsblog

djangocms-blog

aldryn-events

 

DJANGO CMS BEST PRACTICES

TO BE CONTINUED...There's more to come!

Content versioning support

Managing draft/live copy version of objects

Your suggestions

A detailed white paper in the next months

GRAZIE!

QUESTIONS?

Recommended