Upload
iacopo-spalletti
View
93
Download
4
Embed Size (px)
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 appblog 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 pluginblog"><div class="bloglatestentries"> {% for post in posts_list %} {% include "djangocms_blog/includes/blog_item.html" with post=post TRUNCWORDS_COUNT=TRUNCWORDS_COUNT %} {% empty %} <p class="blogempty">{% 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'̂otherblog/', 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:postslatest'
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="blogcontent">{% render_placeholder post.content %}{% else %} <div class="blogcontent">{% 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="blogcontent">{% 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/761ed2d2cd6e41dbab72e2e0c613f903/djangobeer.jpg"<meta property="og:type" content="Article"><meta property="article:published_time" content="20140918 18:03:20"<meta property="article:modified_time" content="20141224 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/761ed2d2cd6e41dbab72e2e0c613f903/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?