Commits

Benoît Bryon committed 155ebaf

Initiated refactoring. Continued overview documentation. UNSTABLE.

Comments (0)

Files changed (9)

-# -*- coding: utf-8 -*-
 """
 Administration interface options of ``templateblocks`` Django application.
 

docs/overview.txt

 *************************
 
 Django-TemplateBlocks tries to bring the block functionality without limiting
-extensions. It focuses on simplicity and reusability. The additional 
-functionalities are covered by extensions.
+extensions. It focuses on simplicity and reusability. Any additional that is
+not required at core level is covered by extensions.
 
 Django-TemplateBlocks is not intended to be a plug-and-play CMS solution. It is
 intended to be a basis on which developers can easily add CMS functionalities 
 to a Django project.
 
+Django-TemplateBlocks can be part of a plug-and-play CMS solution if packaged
+with extensions.
+
 ******************************
 Django-TemplateBlocks concepts
 ******************************
 Block
 -----
 
-A block is an instance of a block-plugin.
-For the developer, it is a Python object, a Django model instance. It 
-implements the "block API" so that it can be handled by core tools and 
-extensions (at least to "render" the block).
-For the template designer, it is a template variable, an object available in
-some particular contexts.
-For the site administrator, it is a piece of information that can be displayed
-on the website. This involves data and theme (layout and style). It can be 
-dynamic or static. Optionally it is customizable.
+Blocks are software components: Python objects that implement a common API.
+
+Blocks look like Django's views. Basically, they take a request as input 
+parameter and return something. The difference with Django's views is that
+they accept a context object as input parameter and do not return HTTP 
+responses.
+
+Block instances are not necessary stored in the database. First of all, they 
+are software components. So in order to respect the separation of software and
+data, they do not own data themselves.
+
+Blocks can be referenced in the database. This makes it possible for the site
+administrator to manage blocks and to attach data to them.
+
+As URL names makes it possible to identify views in Django, a system exists to
+identify blocks. This system makes it possible to get the database objects
+corresponding to a block, and to get the block corresponding to database 
+objects.
+
+As URL names are not necessary related to the corresponding view (an URL name 
+can stand for different views depending on the project), block names are not
+necessary related to a given class or instance. This means that blocks can be
+mapped to names (and vice-versa). Then, the other components (in database, in
+templates), names are used rather than class names. Database or template 
+components do not care about how the functionality is implemented. They only
+have to know how to use a named-block.
+
+As URL configuration files, block names are configuration files.
 
 Block plugin
 ------------
 
-A block plugin is a Python class or Django model which instances are blocks.
-It provides the block functionality by implementing an API.
+A block plugin is a block extension. The base Block class do not provide any
+functionality. Block plugins implement functionalities.
 
 Plugins are made available for the site administrator. The site administrator
 uses plugins to create block instances.
   functionality (which is not so generic since it requires a hack to fit
   specific needs)
 
+Architecture
+============
+
 Core
-====
+----
 
 Block and plugin base classes are Django-TemplateBlocks core.
 
 The following elements should be part of the core:
 
 * block and plugin base classes
+
+Extensions
+----------
+
+The following elements should be handled by extensions:
+
 * a template tag to fetch and render a list of block instances in templates
 * block admin base. Some base forms and admin views
 * plugin management base (installation, configuration, admin...)
-
-Extensions
-==========
-
-The following elements should be handled by extensions:
-
 * regions. Site administrator groups blocks in regions. This is also called
   "slots" or "areas" in some CMS. In a region, blocks are ordered. Regions are 
   used in templates to render a filtered-list of blocks.
   are filters that can be applied when requesting a list of blocks in templates.
 * plugins.
 
+Proof of concept functionalities
+--------------------------------
+
+The following core + extensions are a good starting point. If they can be
+implemented, then the Django-TemplateBlocks project have chances to survive.
+
+* block and plugin base classes
+* a {% render_blocks %} template tag
+* regions in admin
+
 Functionalities
 ===============
 
 AJAX loading
 ------------
 
+Since a page is made of blocks, one could imagine that a page loading consists
+in several asychronous block loadings. This requires an extension to create
+views that handle only one block. It requires careful exception handling (what
+if the requested block cannot be rendered?).
 
 Blocks in content, as fields
 ----------------------------
 Blocks in WYSIWYG content
 -------------------------
 
+
+Block names and declaration
+---------------------------
+
+The developer:
+
+* installs block plugins (software components)
+* declare which blocks are installed
+* for each extension, such as block administration, declare which blocks 
+  plugins are available.
+* declare block names
+* maps block names to installed blocks
+
+The site administrator uses block names. In fact, it corresponds to block 
+plugin names.
+
+Block middlewares
+-----------------
+
+Let's consider an example to illustrate this functionality...
+
+The {% render_blocks %} template tag makes it possible to display a list of
+blocks in templates.
+The list of blocks is typically a list of instances that have been configured
+by the site administrator.
+But what if the developer wants to add "automatic" blocks? or wants to apply
+some filters or modifiers to the block list before it is rendered?
+The developer needs some kind of middleware functionality.
+
+For each functionality which makes use of blocks, the developer may be able
+to add filters or modifiers. This is implemented by extensions. An example
+pattern is provided along with the {% render_blocks %} template tag extension.
+
+Graphic themes and styles
+-------------------------
+
+A block could be shared accross several websites or a website could allow the
+user to switch between graphic themes.
+
+So blocks could have several "theme" configurations.
+
+In administration interface, one could imagine that the site administrator
+does the following operations:
+
+* choose the website he wants to configure
+* choose the graphic theme he wants to configure
+* create or edit a block
+* edit theme-related options for a block
+
+Several styles can be applied within a particular theme.
+As an example, for a "embedded video player" block plugin, you could have a
+"mini" style with few controls and options, and a "full" style with lots of
+controls and options.
+
+Styles may be theme-dependant.
+
+So in administration interface, one could imagine that the site administrator
+does the following operations:
+
+* choose the website he wants to configure
+* choose the graphic theme he wants to configure
+* create or edit a block
+* edit theme-related options for a block
+* choose a style to apply to the block
+* edit style-related options for a block
-from templateblocks.models import Block
-# -*- coding: utf-8 -*-
 """
 Django-TemplateBlocks utilities.
 """
 from templateblocks.models import Block, Plugin
 
 
+
 class PluginEntry():
     def __init__(self, path, model, admin=None):
         self.path = path
-# -*- coding: utf-8 -*-
 """
 Managers of ``templateblocks`` Django application.
 
-# -*- coding: utf-8 -*-
 """
 Models of ``templateblocks`` Django application.
 
 """
-# Django
 from django.conf import settings
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes import generic
 from django.db import models
 from django.db.models import signals
 from django.utils.translation import ugettext_lazy as _
-# Templateblocks
+
 from templateblocks import settings as templateblocks_settings
 from templateblocks import signals as templateblocks_signals
 
 class Block(models.Model):
     """
-    Base template block. This model lets the admin organize the block structure.
-    The Block model is the bridge between plugins and templates.
+    Central model for blocks.
     """
-    code = models.CharField(
-        _('code'),
-        max_length=80,
-        db_index=True,
-        blank=True,
-        editable=False,
-        unique=True,
-        help_text=_('Code that makes it possible to "call" the block within templates.'),
-    )
     plugin_type = models.ForeignKey(
         ContentType,
         blank=True,
     plugin_id = models.PositiveIntegerField(
         blank=True,
         null=True,
-        help_text=_('Identifier of the plugin.'),
+        help_text=_('Identifier of the plugin instance.'),
         editable=False,
     )
     plugin = generic.GenericForeignKey('plugin_type', 'plugin_id')
     
     class Meta:
         abstract = True
-        verbose_name = _('plugin')
-        verbose_name_plural = _('plugins')
+        verbose_name = _('block plugin')
+        verbose_name_plural = _('block plugins')
     
     def __unicode__(self):
         return u'%s' % self.plugin_name
     def render(self, request, template_context=None):
         raise NotImplementedError('Plugin subclasses MUST override the render() method')
     
+    def get_plugin_code(self):
+        raise NotImplementedError('Plugin subclasses MUST override the plugin_code property or the get_plugin_code() method')
+    plugin_code = property(get_plugin_code)
+    
     def get_plugin_name(self):
         raise NotImplementedError('Plugin subclasses MUST override the plugin_name property or the get_plugin_name() method')
     plugin_name = property(get_plugin_name)
     def get_block(self):
         return self.blocks.all()[0]
     block = property(get_block)
-
-
-class HelloWorldPlugin(Plugin):
-    """
-    A minimalist plugin that says "Hello world !". This is a "proof of concept"
-    plugin.
-    """
-    plugin_name = _('hello world')
-    plugin_description = _('Displays "Hello world !"')
-    
-    class Meta:
-        """
-        Model metadata.
-        """
-        verbose_name = _('Hello world plugin')
-        verbose_name_plural = _('Hello world  plugins')
-    
-    def render(self, request, template_context=None):
-        """
-        Returns "Hello world !".
-        """
-        return u'Hello world !'
-
-
-class DirectToTemplatePlugin(Plugin):
-    """
-    A simple plugin that renders a template. The template name is automatically
-    computed from the code of the corresponding block (slot code in template).
-    """
-    plugin_name = _('direct to template')
-    plugin_description = _('Renders a template')
-    
-    class Meta:
-        """
-        Model metadata.
-        """
-        verbose_name = _('Direct to template plugin')
-        verbose_name_plural = _('Direct to template plugins')
-    
-    def _template_names(self, request, template_context=None):
-        """
-        Returns a list of template names, for use with select_template.
-        """
-        return ['templateblocks/%s.html' % self.block.code]
-    
-    def render(self, request, template_context=None):
-        """
-        Renders a template.
-        """
-        from django.template.loader import select_template
-        t = select_template(self._template_names(request, template_context))
-        if template_context is None:
-            output = t.render()
-        else:
-            if isinstance(template_context, dict):
-                template_context = Context(template_context)
-                output = t.render(template_context)
-            else:
-                template_context.push()
-                output = t.render(template_context)
-                template_context.pop()
-        return output
-
-
-class SimpleContentPlugin(Plugin):
-    """
-    A plugin that stores a customizable text value and returns it as rendering.
-    """
-    plugin_name = _('simple content')
-    plugin_description = _('Displays the content you set up.')
-    
-    content = models.TextField(
-        _('content'),
-    )
-    
-    class Meta:
-        """
-        Model metadata.
-        """
-        verbose_name = _('Simple content plugin')
-        verbose_name_plural = _('Simple content plugins')
-    
-    def render(self, request, template_context=None):
-        """
-        Renders a template.
-        """
-        return self.content
-
-# -*- coding: utf-8 -*-
 """
 Settings of ``templateblocks`` Django application.
 """
-# -*- coding: utf-8 -*-
 """
 Signals of ``templateblocks`` Django application.
 
Add a comment to this file

templateblocksplugins/__init__.py

Empty file added.

templateblocksplugins/models.py

+"""
+Models of ``templateblocks`` Django application.
+
+"""
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+
+from templateblocks.models import Plugin
+
+
+class HelloWorldPlugin(Plugin):
+    """
+    A minimalist block that says "Hello world !".
+    This is a "proof of concept" plugin.
+    """
+    plugin_code = 'hello_word'
+    plugin_name = _('hello world')
+    plugin_description = _('Displays "Hello world !"')
+    
+    class Meta:
+        verbose_name = _('Hello world block')
+        verbose_name_plural = _('Hello world blocks')
+    
+    def render(self, request, template_context=None):
+        """
+        Returns "Hello world !".
+        """
+        return u'Hello world !'
+
+
+class StringPlugin(Plugin):
+    """
+    A block that stores a customizable string value and returns it as rendering.
+    The value is not considered safe.
+    """
+    plugin_code = 'string'
+    plugin_name = _('string')
+    plugin_description = _('Displays the content you set up.')
+    
+    content = models.CharField(
+        _('content'),
+        max_length=250,
+    )
+    
+    class Meta:
+        """
+        Model metadata.
+        """
+        verbose_name = _('String block')
+        verbose_name_plural = _('String blocks')
+    
+    def render(self, request, template_context=None):
+        """
+        Returns the instance's content.
+        """
+        return self.content
+
+
+class TextPlugin(Plugin):
+    """
+    A block that stores a customizable text value and returns it as rendering.
+    The text is not considered safe.
+    """
+    plugin_code = 'text'
+    plugin_name = _('text')
+    plugin_description = _('Displays the content you set up.')
+    
+    content = models.TextField(
+        _('content'),
+    )
+    
+    class Meta:
+        """
+        Model metadata.
+        """
+        verbose_name = _('text block')
+        verbose_name_plural = _('text blocks')
+    
+    def render(self, request, template_context=None):
+        """
+        Returns the instance's content.
+        """
+        return self.content
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.