Upgrade to Pro — share decks privately, control downloads, hide ads and more …

django CMS Best Practices

django CMS Best Practices

Given at London Django Meetup @ Skills Matters 09 June 2015, PyCon Italia 2015

http://pyvideo.org/pycon-italia-2015/djangocms-best-practices.html

Iacopo Spalletti

June 09, 2015
Tweet

More Decks by Iacopo Spalletti

Other Decks in Programming

Transcript

  1. WHO AM I? Founder and Lead developer @NephilaIt django CMS

    core developer django CMS installer author
  2. DJANGO CMS BEST PRACTICES WHY? Writing Django applications is easy

    Writing effective and clean Django applications requires some effort
  3. DJANGO CMS BEST PRACTICES WHAT'S THAT? Guidelines being developed by

    the core team Community feedback My experience
  4. 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
  5. DJANGO CMS BEST PRACTICES CAVEATS Nowhere near comprehensive Still in

    flux Task for 2015: Define the best practices Code hooks into django CMS core
  6. DJANGO CMS BEST PRACTICES YET ANOTHER BLOG EXAMPLE Standard blog

    features Pluggable onto multiple pages with different configurations Integration with social networks Integration with full-text search
  7. DJANGO CMS BEST PRACTICES THE BASICS always 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)
  8. DJANGO CMS BEST PRACTICES THE DETAILS Templates inheritance Namespace configuration

    django CMS Frontend editor django CMS Toolbar Meta tags Haystack integration
  9. DJANGO CMS BEST PRACTICES LET'S START We will use djangocms_blog

    as a base List of posts Post detail view Tags Categories Comments ...
  10. DJANGO CMS BEST PRACTICES TEMPLATES INHERITANCE Use 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 %}
  11. DJANGO CMS BEST PRACTICES TEMPLATE RULES Extends CMS_TEMPLATE variable Define

    a conventional block each application should redefine We'll see the meta_mixin/meta.html include later
  12. DJANGO CMS BEST PRACTICES TEMPLATES LAYOUT Use 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 {% empty %} <p class="blog-empty">{% trans "No article found." %}</p> {% endfor %} </div> </div>
  13. DJANGO CMS BEST PRACTICES NAMESPACE SUPPORT Django 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_matc
  14. DJANGO CMS BEST PRACTICES DJANGO CMS SUPPORT django CMS just

    uses Django's own class BlogApp(CMSApp): name = _('Blog') urls = ['djangocms_blog.urls'] app_name = 'djangocms_blog' apphook_pool.register(BlogApp)
  15. 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): pass setup_config(NewsBlogConfigForm, NewsBlogConfig)
  16. DJANGO CMS BEST PRACTICES ALDRYN-APPHOOKS- CONFIG Integrated with django CMS

    namespace instance creation Definition of per-namespace instance options Tied to each model instance class Post(ModelMeta, TranslatableModel): ... app_config = models.ForeignKey(BlogConfig, verbose_name=_('app. config'))
  17. DJANGO CMS BEST PRACTICES IN VIEWS AppConfigMixin: 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
  18. DJANGO CMS BEST PRACTICES IN THE ADMIN Use ModelAppHookConfig to

    get options values (e.g. in admin forms) class PostAdmin(EnhancedModelAdminMixin, FrontendEditableAdminMixin PlaceholderAdminMixin, TranslatableAdmin, ModelAppHookConf admin.ModelAdmin): app_config_values = { 'default_published': 'publish' }
  19. DJANGO CMS BEST PRACTICES IN THE TEMPLATE Access 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 %}
  20. DJANGO CMS BEST PRACTICES DJANGO CMS FRONTEND EDITOR Base for

    plugins behaviour A wrapper around standard Django admin Available for all Django applications
  21. DJANGO CMS BEST PRACTICES USE IT! Add FrontendEditableAdminMixin class PostAdmin(FrontendEditableAdminMixin,

    PlaceholderAdminMixin, TranslatableAdmin, admin.ModelAdmin): model = Post frontend_editable_fields = ('title', 'abstract', 'post_text') ...
  22. 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
  23. DJANGO CMS BEST PRACTICES HOW TO IMPLEMENT IT Toolbar is

    very rich and powerful I'll just show the basics Check documentation for details http://django-cms.rtfd.org/en/develop/how_to/toolbar.html
  24. DJANGO CMS BEST PRACTICES HOW TO IMPLEMENT IT Create cms_toolbar.py

    Define the links to the admin views @toolbar_pool.register class 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)
  25. DJANGO CMS BEST PRACTICES HOW TO IMPLEMENT IT Add 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_objec return context
  26. DJANGO CMS BEST PRACTICES SOME NOTES Redirect 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
  27. DJANGO CMS BEST PRACTICES SHARE THE PASSION! Content is dumb

    without metadata schema.org OpenGraph ... Metadata defines the meaning of the content
  28. DJANGO CMS BEST PRACTICES DJANGO CMS HAS GOT THAT COVERED!

    django-meta / django-meta-mixin Django applications to format document metadata: title author image ...
  29. DJANGO CMS BEST PRACTICES AN EXAMPLE Define an attribute that

    maps metadata properties to attribute/function/callable Include a template ... That's all
  30. 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):
  31. DJANGO CMS BEST PRACTICES THE VIEW as_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
  32. DJANGO CMS BEST PRACTICES THE TEMPLATE Templates are even easier

    <head> ... {% include "meta_mixin/meta.html" %} ... </head>
  33. DJANGO CMS BEST PRACTICES IT'S DONE <meta property="og:title" content="L'evento Djangobeer

    a Firenze, organizz <meta property="og:url" content="http://www.nephila.it/it/blog/2014/09/18/ <meta property="og:description" content="La prima Djangobeer a Firenze: co <meta property="og:image" content="http://www.nephila.it/media/filer_publi <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, organiz <meta name="twitter:url" content="http://www.nephila.it/it/blog/2014/09/18 <meta name="twitter:description" content="La prima Djangobeer a Firenze: c <meta name="twitter:image:src" content="http://www.nephila.it/media/filer_ <meta name="twitter:creator" content="@NephilaIt"> <meta name="twitter:site" content="@nephilait"> <link rel="author" href="https://plus.google.com/+NephilaIt"/>
  34. DJANGO CMS BEST PRACTICES THE IMPORTANCE OF BEING INDEXED 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
  35. DJANGO CMS BEST PRACTICES HOW TO CREATE THE INDEX search_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=
  36. 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'
  37. DJANGO CMS BEST PRACTICES CONFUSED? It may looks complex at

    first Have a look at other examples aldryn-newsblog djangocms-blog aldryn-events
  38. 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