Ella CMS¶
Ella is a Content Management System based on Python web framework Django with a main focus on high-traffic news websites and Internet magazines.
It is composed from several modules:
- Ella core is the main module which links the rest together. It defines architecture on which other modules are built but doesn’t do anything really usefull all alone.
- Ella core plugins are plugins that are shipped in one package together with Ella. There are articles and positions which we consider to be a basic toolbox for each Ella site.
- Other Ella plugins are standalone applications (and therfore not shipped with the core) that provide some specific functionality using Ella’s architecture. We can mention polls, galleries, quizes and many more.
Feature highlights:
- Simple organization of content based on categories
- Efficent implementation of the published content
- In-build photo formating backend
- Django-admin ready
- Plugin system
- Flexibile
- Scalable
- Extensible
- Caching-friendly
- Well tested
- Proven in production environment
For creating site using Ella, working knowledge of Django and its templating language is required. It is therfore highly recommended to get familiar with Django before you try to dwell into Ella. You can start in Django documentation.
Documentation¶
Contents:
Quickstart¶
Setting up Ella¶
This tutorial will guide you through the process of creating and deploying your first Ella-based site. Since Ella is a CMS, we will create a blog. This first step will take us through setting up our environment, installing all the dependencies and kicking off the project. Before you dive into it, we suggest you go through the official Django tutorial to get yourself familiar with Django since we will be relying on that.
Dependencies¶
We assume that python
, setuptools
and python-imaging
(PIL
) are
installed on your system directly since they can be non-trivial to install the
python way. We will be working with pip and virtualenv which are great
tools for any Python project.
Note
We will not cover any version control, but we strongly advise you use some (we prefer GIT) to keep track of your emerging project.
First we need to install virtualenv
(under root):
easy_install virtualenv
Now we can create and activate a virtualenv where our project and all related code will reside:
virtualenv ella_sandbox
source ella_sandbox/bin/activate
Next, install Ella into your fresh virtualenv. Ella has all it’s dependencies
covered in it’s setup, so it’s fairly sufficent to run following command
using pip
:
pip install ella
After these steps, everything required is ready and we can create a new Django project using Ella in standard Django way:
mkdir ellablog
cd ellablog
django-admin.py startproject ellablog
settings.py
¶
Our first step in actual code will be adding Ella to your project’s
INSTALLED_APPS
along with some required settings, the resulting values
(unchanged values are omitted) should look similar to this:
...
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.redirects',
'ella.core',
'ella.photos',
'ella.articles',
)
...
In order to create our new blog, we are gonna need some HTML templates showing
post listings, post details, hompage etc. Therefore, we have to tell
Django, where to look for those templates. This settings are kept in
settings.py
contained in root of our project. Second, we need to specify
a directory + URL used to serve media files from:
Note
Media files and static files are not the very same thing. We consider media files those, that are uploaded dynamically by users, e.g. main article photos. On the other hand, static files usually don’t change and their common representatives include CSS styleseets, JS sources etc.
from os.path import join, dirname
PROJECT_ROOT = dirname(__file__)
# set the templates directory
TEMPLATE_DIRS = (
join(PROJECT_ROOT, 'templates'),
)
# give Django media settings
MEDIA_ROOT = join(PROJECT_ROOT, 'media')
MEDIA_URL = '/media/'
This will tell Django, that it should look for the templates in directory
templates
which is located in the root of the project directory. And
store the media in PROJECT_ROOT/media/
directory.
urls.py
¶
Last thing to configure is the URL mappings. We want to include ella.core.urls
which handle all the Ella magic but also create some mappings that will
serve our static files (and static files for admin) in the development server.
Note that these patterns for static files will work only when DEBUG
mode
is turned on since it would be rather inefficent in production (for more on
this topic, see Managing static files section in Django docs). In similar
fashion, serve also media files discussed in previous paragraph:
from django.conf.urls.defaults import *
from django.conf import settings
from django.contrib import admin
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
# make sure to import ella error handlers
from ella.core.urls import handler404, handler500
# register apps for Django admin and let the apps do any initialization they need
from ella.utils.installedapps import call_modules
call_modules(('admin', 'register', ))
urlpatterns = patterns('',)
# actual URL mappings
urlpatterns += patterns('',
# serve media files
(r'^%s/(?P<path>.*)$' % settings.MEDIA_URL, 'django.views.static.serve', { 'document_root': settings.MEDIA_ROOT, 'show_indexes': True }),
# run Django admin
(r'^admin/', include(admin.site.urls)),
# enable Ella
(r'^', include('ella.core.urls')),
) + staticfiles_urlpatterns()
Note
Instead of calling admin.autodiscover
we are using Ella’s
call_modules
which is a more generic version of the same thing. and
allows us to load additional modules - namely register.py
where, by
convention all Ella apps put the codethey need for their initialization
(connecting signal handlers, registering custom
urls etc.)
Database¶
Last configuration step is the database settings. Ella supports all Django DB backends. Example configuration for MySQL can look like this:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'ellablog',
'USER': 'user',
'PASSWORD': '',
'HOST': '',
'PORT': '',
}
}
To make this work, you should make appropriate database by your custom
DB-related tool (such as command-line tool mysql
in Linux-like operating
systems). After creating the database, you can proceed with creating all the
required tables by Django for you (and admin user during this process):
python manage.py syncdb
Congratulations, you should have a working Ella project. If you start the development server by typing:
python manage.py runserver
try to load the site’s root. If everything worked out, you should get a welcome screen looking similar to this:

Now when we have a working project, we need to actually create the site in the
admin interface. To use it, go to /admin/
and log in using credentials
you entered when creating your superuser account during the syncdb
command.
While being there we will also create an article - our very first blog post so
that we can actually have something to work with in our templates in the next
step of the tutorial.
Note
If you are impatient to start, just play around with the admin to create
one instance of ella.core.models.Category
to get the root of the web
working and then one ella.articles.models.Article
published in that
category (you might need to create additional model like Author
on the
way).
First we need some theory on how Ella handles sites, categories and published objects though.
Ella sites and categories¶
Ella was designed to serve several sites from a single database. It does so by
using Django’s built-in sites framework. The sites
app creates a
default Site
called example.com
during the syncdb
command. Just
rename the domain name to relevant value and you will have an Ella site,
just empty.
Within sites, Ella organizes content into categories. Categories (instances
of ella.core.models.Category
) are organized in a tree for each site. Every
site needs to have exactly one what we call root category - a category without
a parent. This category then represents the root of the website (/
).
Categories are represented by their tree_path
- a path of slugs
from
root category, for example with categories layout:
Ella Blog
About
Technology
Concepts
Django
Django applications
Typical deployment env
the tree_path
values would be:
Category | tree_path attribute |
---|---|
Ella Blog | |
About | about |
Technology | technology |
Concepts | technology/concepts |
Django | technology/django |
Django applications | technology/django/django-applications |
Typical deployment env | technology/typical-deployment-env |
Category
‘s URL is it’s tree_path
(which is what makes the root category
the root of the site) and every post in Ella belongs to one or more categories,
nothing shall exist outside of the category tree.
Publishable
object¶
The main objective of Ella is publishing content. Ella together with it’s
plugins provides several types of content (Article
,
Gallery
, Quiz
, ...) and can be easily extended to add more (just define
the model) or used with existing models.
For ease of manipulation and efficiency, all content models inherit from
ella.core.models.Publishable
. This base class has all the fields needed to
display a listing of the content object (title
, description
, slug
,
photo
), basic metadata (category
, authors
, source
). When using
Ella API you will always receive an instance of the actual class (Article
)
and not the base class (Publishable
). If you have access to only a
Publishable
instance the target
property will return instance of the
correct class (it holds a reference to it’s ContentType
).
Information about publication are also kept on the Publishable
model
(attributes published
, publish_from
, publish_to
and static
).
All these information together are used to create an URL for the object
which will point to it’s detail (e.g. article content). There are two types
of publication with slightly different use cases:
time-based has URL containing the date of publishing and should be used for objects that have some relevance to date (most of the content presumably since Ella was designed to power magazines and news sites). The URL of an object published in time-based way will look like:
/category/tree/path/[YEAR]/[MONTH]/[DAY]/[CONTENT_TYPE_NAME]/slug/
so for example:
/about/2007/08/11/ella-first-in-production/
static has no date in it’s URL and should be used for objects with universal validity. URL of statically published objects contains a primary key reference to avoid namespace clashes:
/category/tree/path/[PK]-slug/
for example:
/about/1-ella-first-in-production/
Just setting up publish information for a Publishable
object makes it
visible (starting from publish_from
) but doesn’t make it appear in any
listing in any Category
. For that you need to specify in which categories
you want it listed.
Listing
object¶
ella.core.models.Listing
instances carry the information in which Category
and when should be a publishable object listed - it enables users to list the
object in as many categories as they wish at arbitrary times (but not sooner
that the Publishable.publish_from
).
By default, listings in the root category only contain Listings
specifically
targeted there whereas listings for any subcategory also contains all the
listings of it’s subcategories. This is a model we found most useful when
working with large sites where the site’s homepage needs to be controlled
closely by editors and the interim categories only serve as aggregators of all
the content published in them either directly or via a subcategory.
Creating a site¶
Now you should have enough information to be able to start exploring the
admin (found on /admin/
) and create your own site and it’s first post.
You will know that you were succesfull if you manage to create and publish an
article whose URL gives you a TemplateDoesNotExist
exception upon
accessing - that means we are ready to create some templates.
Basic templates¶
Now that we have some sample data to work with we can finally start creating the templates we need to get the site running.
Note
For more information on what templates Ella uses and what context is passed in, have a look at Template overview.
page/category.html
¶
First we will create a template rendering a category: page/category.html
.
This is a default template that will be used for all categories if their
specific template (one with their path
) isn’t found. The two most important
variables in the context we want to use is {{ category }}
containing the
Category
model itself and {{ listings }}
containing a list of
Listing
objects for that category ordered by publish_from
and/or
priority.
The basic template will look like:
<h1>Welcome to category {{ category.title }}</h1>
<p>{{ category.description }}</p>
{% for listing in listings %}
<p>
<a href="{{ listing.get_absolute_url }}">{{ listing.publishable.title }}</a>
{{ listing.publishable.description|safe }}
</p>
{% endfor %}
That will render the category title, description and a list of objects published
in that category. Upon accessing /
you should then see the name of the
category and the article you created in administration.
page/listing.html
¶
This template represents the archive, it gets the same context as
page/category.html
and the same code can be used. We will use the same code:
{% extends "page/category.html" %}
page/object.html
¶
As with page/category.html
, page/object.html
is a fallback template that
will be used for rendering any object if more suitable template isn’t found.
In real life we will probably have different templates for different content
types, but to verify the concept and get us started a simple template should
be enough:
<h1>{{ object.title }}</h1>
<p>Published on {{ placement.publish_from|date }} in category: <a href="{{ category.get_absolute_url }}">{{ category }}</a></p>
{% render object.description %}
This template will have access to the actual Publishable
subclass instance
(Article
in our case), as opposed to page/category.html
and
page/listing.html
which only gets instance of Publishable
by default.
Note the use of {% render %}
templatetag that is used to render rich-text
fields (which object.description is) thorought Ella.
Error pages¶
By importing handler404
and handler500
in our urls.py
, we turned
over the control of error pages to Ella. This means that we need to create two
additional templates: page/404.html
:
<h1>Oops, nothing here</h1>
and page/500.html
:
<h1>If you see this, let us please know how you did it, thanks!</h1>
Now that we have a set of rudimentary templates, we can try doing something useful with them.
Enhancing templates¶
Since Ella is a regular Django application, even it’s templates are just plain Django templates. Therefore we just refer you to other sources and Common gotchas & FAQs section to learn more about the templating language and it’s best practices, we will try to focus just on Ella-specific parts.
Boxes¶
First change we will make is abstract the rendering of the object listing on
category homepage and archive. To do this, Ella provides a Box
for
individual objects. It’s primary use is as a
templatetag
. Boxes can be rendered
for objects accessible through a variable or through a database lookup:
{% box <box_name> for <object> %}{% endbox %}
or
{% box <box_name> for <app.model> with <field> <value> %}{% endbox %}
What {% box %}
does is a little more then fancy include - it retrieves the
object, find the appropriate template and renders that with object-specific
context. The context can be quite different for an Article or Photo gallery.
Boxes are usually used throughout an Ella site to provide maximum flexibility
in rendering objects and also for embedding objects into rich text fields stored
in the database (in text of an article for example). Some applications (
Defining positions on the page for example) also use boxes to represent objects.
To create our first box, we just need to create a template called
box/listing.html
containing:
<p>
<a href="{{ object.get_absolute_url }}">{{ object.title }}</a>
{% render object.description %}
</p>
And change page/category.html
to use the box instead of manually specifying
the output:
<h1>Welcome to category {{ category.title }}</h1>
<p>{{ category.description }}</p>
{% for listing in listings %}
{% box listing for listing %}{% endbox %}
{% endfor %}
If you still struggle, why the bloody Box
is used instead of standard
{% include SOMETHING %}
, keep in mind following advantages:
They know which template to use with proper fallback engine.
- The provide class-specific context so that an Article can have
different context than Photo.
Template fallback mechanisms¶
In last step we created a few templates that should suffice for an entire site based on Ella. In real life you probably wouldn’t want every category and every object to share the same template. Ella provides a simple mechanism to target your templates more directly.
Let’s say that we want to create a specific template for rendering articles,
just create a template called page/content_type/articles.article/object.html
and you are done - next time you visit some article’s URL, this template will
get rendered instead of your page/object.html
. This template would be a
good place to render the text of an article for example:
{% extends "page/object.html" %}
{% block content %}
{% render object.content %}
{% endblock %}
Now if you just define the appropriate block in your page/object.html
:
<h1>{{ object.title }}</h1>
<p>Published on {{ object.publish_from|date }} in category: <a href="{{ category.get_absolute_url }}">{{ category }}</a></p>
{% render object.description %}
{% block content %}{% endblock %}
You should be able to see your article’s text on the web.
Another way you can override your templates is based on Category
. For
example if you want to create a custom template for your root category (and
your root category’s slug is ella-blog
), just create one called
page/category/ella-blog/category.html
:
<h1>Welcome to site {{ category.site }}</h1>
<p>{{ category.description }}</p>
{% for listing in listings %}
{% box listing for listing %}{% endbox %}
{% endfor %}
You will be greeted into the site and not your root category next time you visit the root of your blog. Just create any subcategory to check it will remain unaffected.
You can use the same simple mechanism (creating new templates) to change the look of your boxes for individual objects as well.
Note
For more detailed explanation of all the possible template names, have a look at Views, Template overview and Templatetags documentation.
I am a Python developer - where do I begin?¶
Developers have always a hard time. Unfortunately, you need to be familiar with the most topics this documentation offers. You will be the key person coders go to get advice from a you simply have to know the answers. This docs are trying to offer you a helping hand and cover most of the topics you will run into when working with Ella. Not only it gives you API reference, it also offers cooking recipes for common headache situations.
In this documentation, we expect you have proficency in these areas:
- Standard Python programming.
- At least rudimentary knowledge in Django:
- Models
- Views
- Templating
- Middleware
- Context processors
- Media/static handling
- Knowledge of web programming paradigms: request, response, ....
Ella always tries to keep things as simple as possible, but, as you probably learned already, it’s not always just possible. If you want get familiar with Ella, it’s always best to start off with Quickstart to get a grasp of core concepts Ella is built upon. Next, continue with reading the docs in Features section. It is recommended to get yourself familiar with all the topics covered in here even though the Caching and Deployment are probably kinda advanced and not strictly required in the first run. If everything goes allright and you don’t feel lost, keep reading in the Common gotchas & FAQs section which covers frequent show-stoppers for new Ella users. Finally, do a fast sprint throught API reference and List of configuration settings to make your overview complete. And, of course - have a look at the code itself. Sometimes it works even better than best docs.
If feeling confused or not happy with the way Ella is presented or just simply having a note, please feel free to let us know! It is always appreciated.
I am a HTML coder - where do I begin?¶
As the creator of the templates, you should first get confident when working with Django templates. You should have good understanding of following concepts:
- What are templates and how they are defined.
- How to work with variables.
- How to use use filters and what they are for.
- What are Django templatetags and how to use them.
- Basic overview of the in-built Django templatetags.
- Template inheritance.
It would also be very handy, if you had basic understanding of how Django itself works, what are views and models. If you are familiar with all the mentioned topics, great! You are ready to jump into Ella right now. Here is a topic walkthrough we think will be ideal for you.
First, start with Quickstart. It covers the core principles in brief detail and should get you in touch with Ella basics. You will get familiar with basic Ella project setup, the most common templates, and the important models Ella is all about. As a next step, go to Features section and try to consume as much as possible from these topics:
- Template fallback mechanisms
- Category detail page
- Object detail page
- Defining positions on the page
- Working with photos
- Working with related objects
- Syndication - ATOM and his RSS friend
If all those topics make sense, you will probably feel at home when going to Common gotchas & FAQs section, which will hopefully give you last remaining pieces of the puzzle. If still having questions, please contact us and give us the very welcomed feedback what is missing in the docs!
Features¶
This section presents core Ella features. It’s recommended to all of the user base. Some parts might be a little heavy for html coders though. It goes from the most basic aspects to the more and more specialized ones. It tries to show the concepts by examples and doesn’t go into the deep descriptions of the API. If you are looking for reference instead, go to the API reference.
As a rule of the thumb, all sections up to the Working with related objects are recommended for an every-day Ella user.
Template fallback mechanisms¶
Templates for rendering categories and publishable objects use fallback mechanism to provide you full control over what is rendered with minimum effort required.
When selecting template to use for given URL, Ella does several things based on what we are dealing with. However, in both cases there is final fallback to default templates which are:
- category.html for a category template
- object.html for an object template
Note
Under some circumstances, category.html can be overriden, see Defining custom template for category for more details.
Selecting template for a category¶
When selecting templates for a rendering of category, Ella uses this set of rules:
Look at the
tree_path
. Try to find a template inpage/category/[TREE_PATH]/category.html
.Example:
- http://www.example.com/category/subcategory/
Ella would first try to find
page/category/category/subcategory/category.html
.
If template was not found in previous step, try to find the template of an direct ancestor providing we have one and it’s not the root category.
Examples:
- http://www.example.com/category/subcategory/subsubcategory/
First, try
page/category/category/subcategory/category.html
, next trypage/category/category/category.html
and stop because the category"category"
is the main one.- http://www.example.com/category/subcategory/
Try
page/category/category/category.html
and stop.- http://www.example.com/category/
Would not try anything, we are already in main category.
- http://www.example.com/
Would not try anything, we are in root.
If template wasn’t found yet, use default template (which is
page/category.html
in most cases).
Selecting template for an object¶
Selecting template for an object adds even more possibilities for the developer.
It also uses content_type
in form of app_label.model_label
(both
lowercased). Example would be: articles.article
, videos.video
and so on.
- Try to find a template in
page/category/[TREE_PATH]/content_type/[CONTENT_TYPE]/object.html
. - Try to find a template in
page/content_type/[CONTENT_TYPE]/object.html
. - Continue in the same way as when selecting a category template except for
using
object.html
instead ofcategory.html
.
Selecting template for a box¶
Lookup for boxes is done in "box"
subdirectory. It then works exactly
the same as for objects, except that the template name is the name of the
box being rendered and last resort is template box/box.html
.
Category detail page¶
Category detail is the very main page of most content websites. In Ella, we do not make any difference for homepages and other categories except for the different URLs. Ella uses categories in several ways:
- For showing your homepage
- For listing content that is published in the category
- As a static page, e.g. for your contact page
Last use case scenario might be little awkward, but the design decision was made to make this as easy as possible. Because main focus of Ella is content-rich websites and online news, static pages are usually not the primary focus of an Ella project. It’s still quite simple to create personal websites though.
Working with category templates¶
When creating category templates, here are some basic rules you can count on:
The template used is by default category.html
using the template fallback
mechanism (for details on that, see Template fallback mechanisms).
You can set the different template for your category using administration.
For details and explanation of the whole concept, have a look at
Defining custom template for category.
Context will always contain at least:
Key | Value |
---|---|
category |
Category object itself. |
is_homepage |
Flag telling you if this is a homepage, see Homepages. |
is_title_page |
Boolean telling you if this is the first page of the listing/archive. |
is_paginated |
Boolean which is True more pages are
available. |
results_per_page |
Number of objects per page. |
page |
Current page shown. |
listings |
Objects listed in the category for this
page. |
content_type |
If filtering by Content Type is active,
this will hold the ContentType instance. |
content_type_name |
Verbose name of content type if Content Type filtering takes place. |
The basic scenario when building up site’s category templates is following:
- Create the base template
page/category.html
. Make this template as generic as possible to enable nice inheritance. Most often, this category will be created as generic, paginated, content listing as seen on most sites using articles. - Create customized template for homepage since it has different layout in
most cases. Use proper fallback to tell
Ella that it should use a different template for HP. It’s as simple as
putting the template to
page/category/[YOUR_HP_SLUG]/category.html
. Also, practice inheritance, make this template using{% extend "page/category.html" %}
. - Create other category templates that need customization. You will most likely end up building some static pages.
Homepages¶
In Ella, a homepage is recognized as the category, that has no parent. Therefore, it is also the root category. Only one such page is allowed for each site that is contained in database.
The URL of homepage is always “/”, so for a domain example.com, full URL of root category would be of course the root of the whole site:
http://www.example.com/
When working with category templates, homepage will set the variable is_homepage
in the template’s context to True
. Thanks to it, something like this is possible:
<!-- in page/category.html -->
{% if is_homepage %}
This is homepage category.
{% else %}
This is not a homepage.
{% endif %}
This makes it very easy to have only one template which covers most of the category pages including homepage. However, you should always consider splitting the HP-specific code to it’s own template when the HP layout is completely different from other categories. This would make your templates much more readable which is always a good thing.
Other categories¶
In most Ella sites, categories other than HP usually serve for content listings or static pages. We’ll demonstrate the basic code for content listing for the sake of completness.
{% extends "page/base.html" %}
{% block content %}
{% block object_listing %}
{% listing 10 for category as category_listing %}
{% for l in category_listing %}
{% box listing for l.publishable %}{% endbox %}
{% endfor %}
{% endblock %}
{% block pagination %}
{% if is_paginated %}{% paginator 5 %}{% endif %}
{% endblock %}
{% endblock %}
Defining custom template for category¶
By default, template used for rendering category is category.html
. You
can override this behavior to use your custom template. This can be useful
when you need to implement several different layouts for your categories.
Suppose we have following layouts:
- Top 4 articles, then listing of 6 more
- Listing of 10 articles without top ones
- Listing of 10 articles without perexes, only big images
If it wasn’t possible to select a template for category, you would need to
override the template for each category diferrent from the base one (let it be
the first one). Using different templates, you can avoid doing so. First, define
the templates in your settings.py
:
# in settings.py
CATEGORY_TEMPLATES = (
('category.html', 'default (top 4 + listing 6)'),
('category_10.html', 'top 10'),
('category_10_no_perex.html', 'top 10 w/o perexes'),
)
Note
To be consistent with the Ella guidelines, please always use category.html
as your base category template.
Next, create the base template. That would be category.html
. It would
be used, when not set otherwise in your Ella administration:
<!-- in page/category.html -->
{% extends "page/base.html" %}
{% block object_listing %}
<!-- show 4 boxes with big images -->
{% listing 4 for category as category_listing %}
{% for l in category_listing %}
{% box listing_big_image for l.publishable %}{% endbox %}
{% endfor %}
<!-- show 6 more regular boxes -->
{% listing 6 from 4 for category as category_listing %}
{% for l in category_listing %}
{% box listing for l.publishable %}{% endbox %}
{% endfor %}
{% endblock %}
Then, you would create category_10.html
template to show only ten same boxes
for listing:
<!-- in page/category_10.html -->
{% extends "page/category.html" %}
{% block object_listing %}
<!-- show 10 same boxes -->
{% listing 10 for category as category_listing %}
{% for l in category_listing %}
{% box listing for l.publishable %}{% endbox %}
{% endfor %}
{% endblock %}
Finally, create the last category_10_no_perex.html
template, that would
define the last layout:
<!-- in page/category_10_no_perex.html -->
{% extends "page/category.html" %}
{% block object_listing %}
<!-- show 10 boxes without perexes -->
{% listing 10 for category as category_listing %}
{% for l in category_listing %}
{% box listing_no_perex for l.publishable %}{% endbox %}
{% endfor %}
{% endblock %}
This way, you don’t need to override template for each of different categories, you just set the layout in your administration. Also, this is widely used when it comes to creating Static pages that don’t ever change.
Object detail page¶
The object detail in Ella terminology is a detail of a publishable object. This can be the article itself, a page showing gallery or a page with a video player we used as example in Plugins section. This would be a main interest for your users, the main source of information on your site.
Similarly to categories, object details use object.html
template. Same
fallback rules apply (see Template fallback mechanisms).
When dealing with object detail, you can be sure the context will provide you with following data:
Key | Value |
---|---|
object |
Publishable subclass instance we are
dealing with. |
category |
Related Category object for this page. |
content_type |
ContentType instance of the object . |
content_type_name |
Verbose name of content type if Content Type. |
Defining templates follows a same pattern as when working with categories:
- Define a generic template that will be used when rendering objects without
some special behavior. In this template, try to use only attributes defined
by
Publishable
model, so it will work for all subclasses correctly. - Define custom templates for objects of different kinds. There would mostly
likely be different templates for articles, galleries etc. These
templates go to
page/content_type/[APP_LABEL].[MODEL_NAME]/object.html
, e.g.page/content_type/articles.article/object.html
. - Define templates for custom layout of object in specific categories. These
might be sometimes required. Imagine a situation when you need an article
detail to look differently in some special category. For example, you can
have normal articles and site news, both of which are internally implemented
as
Article
instances. It makes sense for site news to keep a little different layout than normal articles do, you probably won’t show the news source and so on.
To provide some real world example of basic object page, have a look at this small snippet:
<!-- in page/object.html -->
{% extends "page/base.html" %}
{% block content %}
<!-- show photo if available -->
{% if object.photo %}
{% box object_main for object.photo %}{% endbox %}
{% endif %}
<!-- show basic information, title, authors, publication date -->
<h1>{% block object_title %}{{ object }}{% endblock %}</h1>
<p>Published at: <span>{{ object.publish_from|date }}</span></p>
{% if object.authors.exists %}
<p>Authors: <strong>{{ object.authors.all|join:", " }}</strong></p>
{% endif %}
<!-- render perex/description -->
{% block perex %}
{% render object.description %}
{% endblock %}
<!-- body for publishable subclasses goes here -->
{% block body %}{% endblock %}
<!-- show related objects -->
{% block related %}
{% related 5 for object as related %}
{% for r in related %}
{% box related for r %}{% endbox %}
{% endfor %}
{% endblock %}
{% endblock %}
Most likely, you would also add following things to the base object template:
- Facebook like button, Twitter tweet button, Google +1 button
- Sharing handlers - send by email, ...
- Tags for the object
- Comments
Object detail URL¶
The URL of Publishable
object detail depends on publication type. As we
already mentioned in Quickstart, there are two:
- time-based publication is limited by
publish_from
-publish_to
period. Outside of these time boundaries, object won’t be reachable on the website. Most websites only usepublish_from
so that the object won’t disappear. - static publication is not limited by time and thus it is unlimited and permanent. Such object will be always reachable on the website.
With time-based publications, objects are given a date stamp in the URL so the namespaces clashes doesn’t happen very often. URL structure goes like:
/category/tree/path/[YEAR]/[MONTH]/[DAY]/[CONTENT_TYPE_NAME]/slug/
So for an example, /about/2007/08/11/articles/ella-first-in-production/
could
be proper result of time-based publication.
With static publication, no date stamp is used. Instead, object’s primary key is prepended before slug to avoid name conflicts. URL structure looks like this:
/category/tree/path/[CONTENT_TYPE_NAME]/[PK]-slug/
And a valid result could be /about/articles/1-ella-first-in-production/
.
Archive pages¶
Rich-text fields: using WYSIWYG editors or a markup language¶
Integrating custom views¶
Ella doesn’t force you to make your views any prescribed way. You can easily create any Django application and add it to your project standard Django way and Ella won’t stand in way.
However, if you try to extend the functionality of the framework itself, you might want to have a look at Ella plugins which offer several simple interface for extending the Ella.
Defining positions on the page¶
Position is understood as placeholder on the page whose context is specific to the category in use. It allows designers to specify areas of the template to be overriden by the site writers, editors via the admin interface. Position is identified by it’s name. Main use case of positions is box embedding, but raw HTML can be used as well.
- inheritance
- When called from the template tag, the application will first try and
locate the active position for the given category, then, if such position
is not available, it will locate active position in the closest ancestor of
the category. This behavior can be overriden by the
nofallback
argument to the{% position %}
templatetag. - tied to objects or raw HTML
- You can either define a generic foreign key to any object whose box you wish to display instead of the templatetag or, if the generic foreign key is empty, raw HTML that you wish to insert.
{% ifposition %}
templatetag- You can check if any position for a given set of names is active using the
{% ifposition %}
templatetag. It behaves in same way as common{% if %}
templatetag.
Note
This feature is part of ella.positions app and thus needs to be added to INSTALLED_APPS before use.
Using positions in your pages¶
Position is defined in the admin interface and used from the templates via two templatetags.
{% position %}
template tag¶
Render a given position for category.
Syntax:
{% position POSITION_NAME for CATEGORY [using BOX_TYPE] [nofallback] %}
...
{% endposition %}
Parameters:
Name | Description |
---|---|
POSITION_NAME |
Name of the position for lookup. |
CATEGORY |
The category for which to render the position -
either a Category instance or category’s
slug . |
BOX_TYPE |
Default type of the box to use, can be overriden from the admin. |
nofallback |
If present, do not fall back to parent categories. |
Text inside the tag (between {% position %}
and {% endposition %}
) is
passed to Box
used for rendering the object. This can also be overriden
from the database.
{% ifposition %}
template tag¶
Render template according to the availability of given position names within given category.
Syntax:
{% ifposition POSITION_NAME ... for CATEGORY [nofallback] %}
POSITION EXISTS!
{% else %}
NO POSITION DEFINED!
{% endifposition %}
Renders ‘POSITION EXISTS!’ if any of the space separated position name is active for the given category, ‘NO POSITION DEFINED!‘ otherwise.
Real world examples¶
Positions are widely used for a lot of page parts that need to be edited by site staff from time to time, like:
- Site menus (see Creating site navigation)
- Page sidebars (see Category-specific sidebars)
- Top articles on the hompage, which are under strict supervision of editors who need to control what exactly and in which order is being displayed.
- Carousel-like content on the bottom of the pages.
<!-- in page/category.html -->
{% load positions %}
...
{% block right_column %}
{% position rightcol_poll for category %}{% endposition %}
{% endblock %}
...
This simple example can be used to show a poll in the page right column in case the poll is defined. It will also switch the poll for the categories where the specific one is defined as stated before.
Working with photos¶
Ella’s core has an integrated photo module which is tightly coupled with the rest of the modules (articles, ...) and plugins, notably the Newman administration plugin.
Features:
- Photo format definition with cross-site option.
- Scaling, cropping.
- Definition of important box for automatic cropping while keeping the important area on the photo intact (e.g.: keeping faces on cropped photo).
{% img %}
template tag for template usage.
Photo module is composed from several important parts:
Photo
model- Photo model stands for the actual photo uploaded by user.
Format
model- Describes different formats that a sites is using. Think of format as a set of rules how to render: “a big photo aligned to right side”, “small photo to show authors face” and so on.
FormatedPhoto
model- This model keeps track of photos that have already been formatted in a given format. It works like a cache so that the formatting only occurs once.
{% img %}
template tag{% img %}
is used when placing the photos in the templates. It simplifies and abstracts the process of thumbnail creation.
Generating thumbnails in the tempalates¶
The {% img %}
template tag is used to get a thumbnail for original Photo
object. It is smart enough to use all the meta info defined on Photo
, so
the important box is taken into account.
Syntax:
{% img <FORMAT> for <VAR> as <VAR_NAME> %}
{% img <FORMAT> with <FIELD_VALUE> as <VAR_NAME> %}
Templatetag supports two approaches. First is very simple, you just give it
a Photo
instance and it will generate thumbnail for it. The second one
tries to find a Photo
you describe by FIELD_VALUE
. See the examples:
{% img category_listing for object.photo as thumb %}
{% img category_listing with pk 1150 as thumb %}
The result (stored as thumb
in the example above) then contains a
FormatedPhoto
instance. This means you can access it’s attributes,
particularly url
method and width
and height
.
Workflow¶
The basic workflow when using photos goes like this:
Define formats. This step is usually already done when you enter the stage as the designer is reponsible for it in most cases. We only need to enter the data to the Ella database.
Store the formats in fixtures is quite important step, because it makes development much easier when a more than one developer is involved. It makes sense to add the fixture as initial data because it shouldn’t be altered in database without an intent.
Use image boxes in your templates. For the thumbnails, use boxes. The snippet below shows how you can embed photos using boxes in an object box we used in Category detail page section.
<!-- in box/listing.html --> <div class="article"> <h2><a href="{{ object.get_absolute_url }}">{{ object }}</a></h2> {% if object.photo %} <a href="{{ object.get_absolute_url }}" title="{{ object.title }}"> {% box category_listing for object.photo %}{% endbox %} </a> {% endif %} </div>
Use
image
templatetag to generate thumbnails. When the photo is embedded, the last remaining step is to generate thumbnails so the photo will fit on the page nicely. To do this, use{% image %}
template tag.<!-- in box/content_type/photos.photo/category_listing.html --> {% load photos %} {% block image_tag %} {% image object in "200x100" as image %} <img src="{{ image.url }}" alt="{% firstof title object.title %}" width="{{ image.width }}" height="{{ image.height }}" /> {% endblock %}
Note
It’s a good habit to use format naming convention which describes the used dimensions (like the “200x100” used in example above) and attributes because:
- It will minimize the number of formats you use and eliminate duplicates.
- It will eliminate the threat that the same image is formatted twice with same parameters.
Using placeholder images during development¶
It is quite common that during development of the Ella application, one doesn’t always have all the photos stated in database on his HDD. This can happen when you share one database dump with co-workers and someone adds new articles etc.
In order to show at least something, Ella provides debugging setting which
will replace the missing image files by placeholder images. You can enable
this by setting PHOTOS_DEBUG = True
in your project settings. By default,
Ella will use web service http://placehold.it to generate the images. Optionally,
you can use your custom placeholder service by changing the PHOTOS_DEBUG_PLACEHOLDER_PROVIDER_TEMPLATE
to your own. Use something like this:
DEBUG_PLACEHOLDER_PROVIDER_TEMPLATE = 'http://placehold.it/%(width)sx%(height)s'
Syndication - ATOM and his RSS friend¶
Ella has automatic syndication support out of the box. For each category, there are RSS a ATOM feeds automatically available on:
www.example.com/feeds/rss/[CATEGORY_TREE_PATH]/
and:
www.example.com/feeds/atom/[CATEGORY_TREE_PATH]/
respectively.
Ella uses Django syndication feed framework internally to render the feeds.
Default number of objects in feed is set to 10 by RSS_NUM_IN_FEED
setting. You can override this setting it to different value in your
settings.py
. Also, you can define an enclosure format by setting
RSS_ENCLOSURE_PHOTO_FORMAT
which defaults to None
.
The value is expected as Format
instance name. If you set this to None
(or don’t set it at all), no enclosures will be used.
The feed title and description defaults to category title
attribute. If you
need to override this, use app_data and
make sure you set following:
category.app_data['syndication'] = {
'title': 'My feed title',
'description': 'My feed description'
}
You can do this through Django administration.
Incorporating plugins¶
Ella design is as lightweight as possible. Prefered way of extending it’s functions is via plugins. Ella provides great flexibility when it comes to plugin possibilities. You can for example:
- Add your custom
Publishable
subclasses. - Create custom
Box
classes for the new publishables. - Add new actions over the
Publishable
objects. - Customize bundled workflow when rendering the content.
We’ve dedicated whole section for plugins, because it’s an important topic and almost every project has it’s specific needs. So, for details, go to Plugins.
Extending category/publishable metadata¶
Since Ella has quite a long history behind it, we’ve gathered lot of experience
from previous fails. One such experience is that almost every project needs
to add aditional data on the bundled models. This can be done in lot of
various ways because of Python’s great possibilities, but more or less, it’s
a dark magic or monkey patching. This is not nice and violates the Django
core principle: explicit is better then implicit. To fix this up, we’ve
added possibility to add arbitrary data on Publishable
, Category
and Photo
models programatically.
Each of the mentioned models has one JSONField subclass AppDataField
called app_data
which can hold any information you need. It has some
limitations though:
- It’s not possible to perform efficent queries over the defined fiels. If
you needed it, add
OneToOne
relation to your custom model instead. - You are responsible of setting the fields correctly, no validation measures are placed on that field so that the data might be corrupted if not used properly.
AppDataField
acts the same way as regular Python dict
object. You can
store any data structure you like provided it’s serializable by Django’s JSON
encoder.
Conventions¶
AppDataField
recognizes namespaces for different applications. The access
is not limited though so that any application can access any namespace. The
namespace is a simple first-level dict key (e.g. ‘emailing’ or ‘my_articles’
in the following examples).
To avoid name clashes, we encourage you to follow this convention so that all your custom data is stored by using a key which coresponds to the app label of aplication storing the data, such as:
# in app "emailing"
p = Publishable()
p.app_data['emailing'] = {'sent': False}
# in app "my_articles"
p = Publishable()
p.app_data['my_articles'] = {'custom_title': 'Foobar'}
Custom container classes¶
By default, Ella returns an AppDataContainer
class when you access a
namespace. This is simply a dict subclass with no additional data except
for the information about the model class it is bound to. However, you
can provide your own classess for the namespaces. This allows you to create
methods working with the your custom data. For example, you can have
CommentsDataContainer
for your comments application which can provide
methods like comment_count
.
Registering your custom container class is very simple. The formula is:
from app_data import app_registry
app_registry.register('comments', CommentsDataContainer, Publishable)
Unregistration works the same way:
app_registry.unregister('comments', Publishable)
app_registry.register('comments', SomeOtherDataContainer, Publishable)
Deployment¶
Plugins¶
Ella tries to keep the core framework as lightweight as possible. This has very good reasons:
- it let’s what is required for your app to your decision
- it minimizes the dependencies of core application
- it makes the development faster, because you can enhance your module while not needing to update the rest of the code
Because of this philosophy, plugins were introduced in version 3.0.0.
Where to get ‘em?¶
Currently, there are only plugins that were created by us directly. 3rd party plugins are hopefully on the way – it depends more o less on you, Mr. Reader :)
Our plugins can be found in our GitHub repository. Here is a list of some interesting ones:
- Newman - use admin forged directly for Ella needs
- Tagging - provides tagging functionality
- Comments - simple threaded comments
- Galleries - create galleries from your photos
- Polls - let users vote for things and compete
- Imports - load stuff from other sites
- Series - create series from articles covering same topic
Basic plugin structure¶
All Ella plugins come as Django applications bundled using setuptools. Each plugin has dependency on the Ella’s core, so Ella is always required and plugins can hardly be used without it.
As Ella provides significant flexibility, plugins are able to do quite a lot of magic, like following:
- Define custom
Publishable
objects via subclassing. For more details, see Subclassing Publishable. - Extend actions performed over the
Publishable
objects, for details, see Overriding Publishable URLs section. - Create custom
Box
classess for fine-tuned includes. This is discussed in detail in section Custom Boxes. - Provide additional methods of listing
Publishable
objects for a category, see Listing Handlers. - Define related finder functions to get related
Publishable
instances, see Related finders.
Plugin API¶
Subclassing Publishable¶
Due to the fact that Publishable
is common Django model, it is possible to
simply extend it with your custom model. When doing this, you effectively adding
your custom model to whole Ella machinery and all publishing-related stuff
is ready for you out-of-the box!
Let’s have a look at real-world example. During this walkthrough, we will try to create a publishable video that will have YouTube video code as source. We will keep it simple and use YouTube’s video player to show the video itself.
The very first step is to create your own application using the standard Django way:
django-admin.py startapp video
After creating the app to hold it, let’s define the class itself. If you are acustomed to Django models, this is going to look very familiar to you.:
# in models.py within your video application
from django.db import models
from django.utils.translation import ugettext_lazy as _
from ella.core.models import Publishable
class YoutubeVideo(Publishable):
code = models.CharField(max_length=20, title=_('Code'))
class Meta:
verbose_name = _('Youtube video')
verbose_name_plural = _('Youtube videos')
def __unicode__(self):
return self.code
Note
If you want to examine whats is going on behind the scenes when subclassing
Django models, have a look at Django model inheritance. We are using
Multi-table inheritance so that each Publishable
subclass has a hidden
pointer - publishable_ptr
- to the Publishable
object. This pointer
also acts as PK in the DB table.
Next step is to put the new app to the settings.:
INSTALLED_APPS = (
'ella.core',
'ella.articles',
...
'yourproject.video',
)
Finally, resync your database so the DB table for the class is created:
django-admin.py syncdb
By defining this, we already have a working publishable object, nothing more is needed. Of course, in real world, you would probably need to do some polishing (adding better title, etc.), but for now, this is enough.
Custom Boxes¶
We have defined our new publishable object, but something still remains a little unclear: how to embed the video in the HTML page. In this part of walkthrough, we will present you a way that is preferred when working with Ella. These are so-called boxes.
As described in Boxes, boxes are something you can call
an include on steroids. Boxes behave very much like standard Django
{% include %}
templatetag, but are suited to be used with publishable
objects. They do following things for you so you don’t need to care about
them:
- Template path resolution
- Object-specific context within the included template
- Ability to accept advanced parameters
Now back to the Video
publishable subclass. What we want to achieve is
that our Video
is being rendered in the page. For this, we will create a
custom Box
subclass. Here is, how a desired result will look when embedding
the video in the page:
<h1>Watch the video right here!</h1>
{% box video_player for video_object %}
width: 400
height: 200
{% endbox %}
The first thing you need to do is to define the box sublcass itself:
# in models.py
from ella.core.box import Box
class VideoBox(Box):
def get_context(self):
context = super(VideoBox, self).get_context()
context.update({
'width': self.params.get('width', '400'),
'height': self.params.get('height', '200')
})
return context
Note the get_context
method. Since width
and height
parameters are
specific to our VideoBox
and not recognized by other boxes, we need to
handle them and pass them into the include context. self.params
is a
dictionary holding parameters used to call the box. We provide sane defaults
when the parameters are not provided so that we can still call the box by using
simple {% box video_player for video_object %}{% endbox %}
.
Next step is to let Ella know, that we want a special type of box to be
used with our Video
. If we didn’t do that, Ella would use a basic Box
class which is missing the width
and height
parameters. To tie our
model with the VideoBox
set the box_class
class variable on the
Video
model:
class Video(Publishable):
...
box_class = VideoBox
...
In order to actually render something we also need to create a HTML template.
Box templates are placed in box
directory within paths where Django template
finders are able to reach them (if you are unsure what a template finder
is, please refer to the Docs). The name of the box also serves as name of
the template to use. In our case, the name of the box is video_player
so
the template name is going to be video_player.html
. Boxes provide a
template search fallback which we’re not gonna discuss here to keep the thing
simple. For further information, see Templatetags.
Our box is fairly simple. We are gonna use the code provided by YouTube and it will look like this:
<!-- in templates/box/video_player.html -->
<iframe width="{{ width }}" height="{{ height }}" src="http://www.youtube.com/embed/{{ object.code }}" frameborder="0" allowfullscreen></iframe>
See how nicely box integrates all things we have so far together. It uses
object.code
to build up the URL and width
and height
attributes to
define the video player dimensions.
Overriding Publishable URLs¶
Adding custom actions¶
Consider a situation, when we would like to have discussion about the video on a separate page while keeping the nice URL prefix Ella creates for it’s publishable objects. There is a simple solution for that. Ella’s custom URL resolver allows us to add actions for the Publishable objects easily.
We would like our URL to have following form:
/about/2007/08/11/videos/ella-first-in-production/discussion/
To do this, we will append a custom view function for the Video
model:
# in yourapp/video/urls.py
from django.conf.urls.defaults import url, patterns
from ella.core.custom_urls import resolver
from yourapp.models import Video
from yourapp.video.views import show_discussion
urlpatterns = patterns('',
url(r'^discussion/$', show_discussion, name='video-show-discussions'),
)
resolver.register(urlpatterns, model=Video)
When registering custom URLs, we use ella.core.custom_urls.resolver
instead
of regular Django url machinery. This does a little Python magic so that your
URLs will be appended to base Publishable URL. Note the use of model
argument in
resolver.register(urlpatterns, model=Video)
This means, that the custom action will be available only for a Video
model.
If we wanted to add our discussion action to all Publishable models, we would
simply omit the model
argument altogether.
As you have probably noticed, we are using show_discussion
view function
without declaring it, let’s fix that up:
# in yourapp/video/views.py
def show_discussion(request, context):
obj = context['object']
return render('yourapp/discussion.html', {'object': obj})
Views that are used with Ella’s resolver always accept request
(which is a
normal Django request object) and context
which is a dictionary that
contains following data:
Key | Value |
---|---|
object |
The publishable object itself. |
category |
Category object related to the URL. |
content_type_name |
Verbose name of Content type of the Publishable (e.g. Article, Video and so on). |
content_type |
ContentType instance for Publishable. |
Overriding objects’ detail¶
Besides custom actions, it is also possible to completely override the view which handles rendering of object detail page. Such a requirement might occur in these situations:
- You need to add custom object-related data to the context in the detail template.
- You wish to change the way the view itself works. This can be used for advanced behavior changes which are needed only rarely.
To define a custom view, we will use the Ella’s URL resolver again:
# in your urls.py
from django.conf.urls.defaults import patterns, url
from ella.core.custom_urls import resolver
from yourapp.models import Video
from yourapp.views import video_detail
resolver.register_custom_detail(Video, article_detail)
This will result in calling our article_detail
view instead of the default
one. Custom detail views are called with same arguments as custom action views.
For reference, see the table with custom view arguments above. For further information
on Ella’s ObjectDetailView
, see Views.
Listing Handlers¶
By default Ella can list Publishable
in categories using the Listing
model. If additional methods of listing, sorting and pagination is required, a
plugin can define a ListingHandler
. For example if makes sense for a
comments plugin to define a ListingHandler
that will allow you to list
Publishables
sorted by number of comments.
Project can define multiple ListingHandler
classes and use GET parameters
and optional arguments to the {% listing %}
template tag to determine which
to use on per-request basis.
On top of the default ListingHandler
('ella.core.managers.ModelListingHandler'
) Ella also provides an optimized
RedisListingHandler
('ella.core.cache.redis.RedisListingHandler'
) to be
used on high traffic sites.
Usage¶
ListingHandler
classes a projects is using are defined in settings, a
configuration entry for 'default'
must always be present:
LISTING_HANDLERS = {
'default': 'ella.core.managers.ModelListingHandler',
'comments': 'ella_comments.CommentCountListingHandler',
}
Interface¶
ListingHandler
is justa class that defines two methods - count
and
get_listings
:
from ella.core.managers import ListingHandler
class CommentsListingHandler(ListingHandler):
def count(self):
...
def get_listings(self, offset=0, count=10):
...
The __init__
method of the class accepts folowing aguments:
category, children=None, content_types=[], date_range=(), exclude=None
Key | Default | Value |
---|---|---|
category |
Category object |
|
children |
NONE |
One of NONE , IMMEDIATE and
ALL indicating whether to include all
Publishables listed in category’s
children/descendants. |
content_types |
[] | ContentType instances to filter on. |
date_range |
() | Optional date range to list. |
exclude |
None | A Publishable instance to omit from the
result. |
API reference¶
If you are looking for the description of the models, views and more, you’re on the right place.
Models¶
Ella core module consist of four apps, two of them contain the main logic and
the second two provide basic CMS capabilities. The core logic is provided by
ella.core
and ella.photos
applications, see the image below for quick
overview of models used. Moreover, Ella ships with two basic CMS apps you can
use: articles and positions. Quick overview image follows.



Core models¶
The Author
model¶
-
class
ella.core.models.
Author
¶
Describes an Author of the published content. Author can be:
- Human
- Organization
- ...
All the fields except for slug
are optional to enable maximum of
flexibility.
-
Author.
user
¶ Optional. Related Django
User
instance. Can be blank and null.
-
Author.
name
¶ Optional. Name of the author.
-
Author.
slug
¶ Required. The only required field is slug. Must be unique.
-
Author.
description
¶ Optional. You may provide description of author.
-
Author.
text
¶ Optional. Small perex about the author. Use together with description to provide information about the author.
-
Author.
email
¶ Optional. When dealing with humans as authors, you can fill up his e-mail.
The Source
model¶
-
class
ella.core.models.
Source
¶
A Source
in oposition to Author
is used for publishable content
that was taken from other sites and it’s purpose is mainly for legal matters.
-
Source.
name
¶ Required. The name of the source.
-
Source.
url
¶ Optional. If source is an organization, you may fill up their URL.
-
Source.
description
¶ Optional. Description about the source.
The Category
model¶
-
class
ella.core.models.
Category
¶
Category
is the basic building block of Ella-based sites. All the
published content is divided into categories - every Publishable
object
has a ForeignKey
to it’s primary Category
. Primary category is then
used to build up object’s URL when using Category.get_absolute_url method.
Besides that, objects can be published in other categories (aka “secondary”
categories) via Listing
.
Every site has exactly one root category (without a parent) that serve’s as the sites’s homepage.
-
Category.
title
¶ Title of the category for common purposes.
-
Category.
description
¶ Optional. Description of the category for common purposes.
-
Category.
content
¶ When rendering static pages, this can come handy. It’s a rich-text powered field capable of holding HTML.
-
Category.
template
¶ Required. Template used for rendering the category. Defaults to
category.html
and can be overriden for custom layouts of the category detail.
-
Category.
slug
¶ Required. Slug for querying the category in URL.
-
Category.
tree_parent
¶ Relation to the parent category. When no parent category exists, the value is
None
and such category is considered as root category. The prefered way of getting the parent isCategory.get_tree_parent
method insted.
-
Category.
main_parent
¶ Returns parent category, which is considered as main. A main category is a category, whose parent is the root category.
-
Category.
tree_path
¶ Path in the category tree from the root. Is composed from the slug fields of the categories on the way joined by “/” symbol. It’s generated automatically.
Example:
"nested1/nested2"
-
Category.
path
¶ Returns tree path of the category. Tree path is string that describes the whole path from the category root to the position of this category.
-
Category.
site
¶ Required. A
Site
fromdjango.contrib.sites
framework, which category belongs to.
-
Category.
app_data
¶ Optional. A JSONField for keeping arbitrary data. See Extending category/publishable metadata for further information.
-
Category.
get_tree_parent
(self)¶ Returns tree parent or
None
if not existent. Cached. Use in favor ofCategory.tree_parent
attribute.
-
Category.
get_absolute_url
(self)¶ Returns absolute URL of the category. Useful in templates and views.
-
Category.
draw_title
(self)¶ Returns title indented by elements that can be used to show users a category tree.
Examples:
- no direct parent (the category root)
- TITLE
- one parent
- &nsbp;TITLE
- on third level of the tree
- TITLE
The Dependency
model¶
-
class
ella.core.models.
Dependency
¶
-
Dependency.
target_ct
¶ ContentType
of theDependency.target
.
-
Dependency.
target_id
¶ Primary key of the
Dependency.target
.
-
Dependency.
target
¶ Target of the dependency relation.
-
Dependency.
dependent_ct
¶ ContentType
of theDependency.dependent
-
Dependency.
dependent_id
¶ Primary key of the
Dependency.target
.
-
Dependency.
dependent
¶ Source of the dependency relation.
The Publishable
model¶
-
class
ella.core.models.
Publishable
¶
Base class for all objects that can be published in Ella.
-
Publishable.
content_type
¶ Automatically managed.
ContentType
instance of the Publishable subclass if applicable. Used to get the subclass instance in case a genericPublishable
parent is dealt with which occurs for example when querying over all publishable objects.
-
Publishable.
target
¶ Automatically managed. Generic foreign key that points to the subclass instance for easy access. Cached to save the queries.
-
Publishable.
category
¶ Required. Main
Category
object aPublishable
instance belongs to. This has significant impact when building up the URL.
-
Publishable.
title
¶ Required. Verbose title of the publishable (gallery name, article title, ...).
-
Publishable.
description
¶ Optional. Basic description of the publishable. Can be used as perex, for instance.
-
Publishable.
slug
¶ Required. Slug to use when building up the URL. Needs to URL-friendly.
Required. A
ManyToMany
relation withAuthor
model to list publishable object’s authors.
-
Publishable.
source
¶ Optional. If the object comes from diferent source which needs to be listed, use this field.
-
Publishable.
photo
¶ Optional. The main photo of publishable objects. Main article photo for example.
-
Publishable.
published
¶ Required. A
BooleanField
instance keeping information if the object is already published or not. Works together withpublish_from
andpublish_to
fields.
-
Publishable.
publish_from
¶ Required. Datetime keeping the start of publication period.
-
Publishable.
publish_to
¶ Required. Datetiem keeping the Finish of publication period.
-
Publishable.
static
¶ Required. A boolean whether the publication is static which means it’s not bound to some special date. Publication is valid forever.
-
Publishable.
app_data
¶ Optional. A container for arbitrary data on the model, for more info, see Extending category/publishable metadata.
-
Publishable.
get_absolute_url
(self, domain=False)¶ Returns absolute URL to the object without the domain and protocol.
Example:
"/news/2012/1/1/some-article-slug/"
-
Publishable.
get_domain_url
(self)¶ Returns full URL to the object with the domain and protocol added.
Example:
"http://www.example.com/news/2012/1/1/some-article-slug/"
-
Publishable.
get_domain_url_admin_tag
(self)¶ Domain url to be used in adminstration for showing the page link.
-
Publishable.
is_published
(self)¶ Returns
True
if the Publishable is currently active,False
otherwise.
The Listing
model¶
-
class
ella.core.models.
Listing
¶
Listing of an Publishable
in a Category
. Each and every object that have it’s
own detail page must have a Listing
object that is valid (not expired) and
places it in the object’s main category. Any object can be listed in any
number of categories (but only once per category). Even if the object is
listed in other categories besides its main category, its detail page’s url
still belongs to the main one.
-
Listing.
publishable
¶ Required. A related
Publishable
instance to define the listing for.
-
Listing.
category
¶ Required. A
Category
instance where the listing should occur.
-
Listing.
publish_from
¶ Required. Datetime with start of the listing period.
-
Listing.
publish_to
¶ Required. Detaime with end of the listing period.
-
Listing.
commercial
¶ Optional. Set to
True
if the listing is a commercial or ad related. These listings are usually marked with an ad warning. Defaults toFalse
.
-
Listing.
get_absolute_url
(self, domain=False)¶ Returns absolute URL to the listing without domain and protocol parts.
Example:
"/news/2012/1/1/some-article-slug/"
-
Listing.
get_domain_url
(self)¶ Returns absolute URL to the list with the domain and protocol.
Example:
"http://www.example.com/news/2012/1/1/some-article-slug/"
Photo models¶
The Photo
model¶
-
class
ella.photos.models.
Photo
¶
Represents original (unformated) photo uploaded by user. Used as source
object for all the formatting stuff and to keep the metadata common to
all related FormatedPhoto
objects.
-
Photo.
title
¶ Required. Human-readable title of the photo.
-
Photo.
description
¶ Optional description.
-
Photo.
slug
¶ Required. Slug to use when creating URL.
-
Photo.
image
¶ Required. Path to the uploaded image file.
-
Photo.
width
¶ Required. Original width of the uploaded image file.
-
Photo.
height
¶ Required. Original height of the uploaded image file.
important_*
attributes describe the rectangular area on the photo, which
shouldn’t be cropped.
-
Photo.
important_top
¶
-
Photo.
important_left
¶
-
Photo.
important_bottom
¶
-
Photo.
important_right
¶
Required. A
ManyToMany
relation withAuthor
model.
-
Photo.
source
¶
-
Photo.
created
¶ Automatically managed. Keeps information when the photo was uploaded.
-
Photo.
app_data
¶ Optional. A container for arbitrary data on the model, for more info, see Extending category/publishable metadata.
-
Photo.
__unicode__
()¶ A human-readable representation of the
Photo
.
-
Photo.
get_absolute_url
()¶ Full URL to the image file.
-
Photo.
get_image_info
()¶ Returns dictionary with keys
url
,width
andheight
holding metainformation about the image.Example:
>>> p = Photo.objects.get(pk=1) >>> p.get_image_info() >>> {'url': 'http://media.example.com/2011/1/23/img.jpg', 'width': 100, 'height': 200}
-
Photo.
ratio
()¶ Returns
float
holding the ratio between width and height ofNone
if not applicable.
-
Photo.
get_formated_photo
(self, format)¶ Returns
FormatedPhoto
instance for givenformat
.
The Format
model¶
-
class
ella.photos.models.
Format
¶
Defines per-site photo sizes together with rules how to adhere to them.
This includes:
- maximum width and height
- cropping settings
- stretch (rescale) settings
- sample quality
-
Format.
name
¶
-
Format.
max_width
¶ Required. Integer with maximum width in pixels of the resulting image.
-
Format.
max_height
¶ Required. Integer with maximum height in pixels of the resulting image.
-
Format.
flexible_height
¶ Required. Boolean if height is “flexible”. If set to
True
, the allowed height will be in rangemax_height
-flexible_max_height
.
-
Format.
flexible_max_height
¶ See
Format.flexible_height
above.
-
Format.
stretch
¶ Required.
True
if stretching can be used to ensure required dimensions. If set toFalse
, only cropping will be used.
-
Format.
nocrop
¶ Required.
True
if this format doesn’t do any cropping.
-
Format.
resample_quality
¶ Requried. Sampling quality to use when performing formating operations. Defaults to 85.
-
Format.
sites
¶ Django
Site
instances that can use the format.
-
Format.
get_blank_img
(self)¶ Returns fake
FormatedPhoto
object to be used in templates when an error occurs in image generation. The result will be a dictionary with keysblank
,width
,height
andurl
which points to storage while usingPHOTOS_EMPTY_IMAGE_SITE_PREFIX
setting.
-
Format.
ratio
(self)¶ Returns
float
holding the ratio between width and height.
The FormatedPhoto
model¶
-
class
ella.photos.models.
FormatedPhoto
¶
Cache-like container of specific photo of specific format. Besides
the path to the generated image file, crop used is also stored together
with new width
and height
attributes.
-
FormatedPhoto.
photo
¶ Related
Photo
instance that is being formated.
-
FormatedPhoto.
format
¶ Related
Format
instance that is being used for formating.
-
FormatedPhoto.
image
¶ Source
Image
instance.
The crop_*
attributes keep information how the cropping was done if
peformed.
-
FormatedPhoto.
crop_left
¶
-
FormatedPhoto.
crop_top
¶
-
FormatedPhoto.
crop_width
¶
-
FormatedPhoto.
crop_height
¶
-
FormatedPhoto.
url
¶ Returns the URL of the resulting photo file.
The Article
model¶
-
class
ella.articles.models.
Article
¶
Article
is the most common publishable object. It can be used for
news on internet news pages, blog posts on smaller blogs or even for
news on an organization’s home page.
Attributes¶
-
Article.
upper_title
¶ Optional. Second title to use for special use cases.
-
Article.
created
¶ Automatically managed. Datetime when the article was created.
-
Article.
updated
¶ Set by user, optional. Datetime when the article was updated. This is not updated automatically and is in the control of users. Can be used for information to the readers when the article was last updated.
-
Article.
content
¶ Required. Rich-text field holding content of the article.
The Position
model¶
-
class
ella.positions.models.
Position
¶
Represents a position – a placeholder – on a page belonging to a certain category.
Attributes¶
-
Position.
name
¶ A human-readable name for the position. This name is also used in templates when using the
{% position %}
and{% ifposition %}
templatetags.
-
Position.
category
¶ A
Category
object for which the position si defined. This is very important and used when resolving whichPosition
object to use for the place defined in template.
-
Position.
target_ct
¶ Optional. Django
ContentType
instance for the object to show in the position. Used together withtarget_id
to find out the finaltarget
.
-
Position.
target_id
¶
-
Position.
target
¶ Optional. Instance of the target object. In case nor
target_ct
nortarget_id
is set, raw HTML is rendered using thetext
field instead.
-
Position.
text
¶ Optional. When no specific object is bound to the position using the
target
attribute, raw HTML in this field is used.
-
Position.
box_type
¶ Optional. Box name to use when rendering
taget
.
-
Position.
active_from
¶ Optional. Datetime holding information when to start showing this position. If kept to
None
, no check is performed.
-
Position.
active_till
¶ Optional. Datetime holding information when to finish showing this position. If kept to
None
, no check is performed.
-
Position.
disabled
¶ Optional. Defaults to
False
. If set toTrue
, position won’t be shown even though it is active.
-
Position.
__unicode__
(self)¶ Human-readable representation of the position.
-
Position.
render
(self, context, nodelist, box_type)¶ Returns the rendered position object. When position is bound to an object, box for the object will be rendered using
box_type
. If no object is specified, raw HTML intext
attribute use used as template.
Views¶
Note
In any template name <tree_path>
stands for the value of
Category.path
, not it’s actual tree_path
. This is because of empty
tree_path
for root categories which would make it impossible to
override a template for anything in the root category and the root category
itself.
-
class
ella.core.views.
ListContentType
¶ List objects’ listings according to the parameters. If no filtering is applied (including pagination), the category’s title page is rendered. The template used depends on
template
attribute for category being rendered. Default template iscategory.html
, so it would look like this:page/category/<tree_path>/category.html
page/category.html
If custom template is selected, let’s say
static_page.html
, it would result in:page/category/<tree_path>/static_page.html
page/static_page.html
If filtering is active, an archive template gets rendered:
page/category/<tree_path>/content_type/<app>.<model>/listing.html
page/category/<tree_path>/listing.html
page/content_type/<app>.<model>/listing.html
page/listing.html
The context contains:
category
listings
: list ofListing
objects ordered by datepage
:django.core.paginator.Page
instanceis_paginated
:True
if there are more pagesresults_per_page
: number of objects on one pagecontent_type
:ContentType
of the objects, if filtered on content typecontent_type_name
: name of the objects’ type, if filtered on content type
Parameters: - category –
tree_path
of theCategory
, root category is used if empty - month, day (year,) – date matching the
publish_from
field of theListing
object. - content_type – slugified verbose_name_plural of the target model, if omitted all content_types are listed
- page_no – which page to display
All parameters are optional, filtering is done on those supplied
Raises Http404: if the specified category or content_type does not exist or if the given date is malformed.
-
class
ella.core.views.
ObjectDetail
¶ Renders a page for publishable. If
url_remainder
is specified, tries to locate custom view viaDetailDispatcher.call_view()
. IfDetailDispatcher.has_custom_detail()
returnsTrue
, callsDetailDispatcher.call_custom_detail()
. Otherwise renders a template with context containing:- object:
Publishable
instance representing the URL accessed - category:
Category
of theobject
- content_type_name: slugified plural verbose name of the publishable’s content type
- content_type:
ContentType
of the publishable
The template is chosen based on the object in question (the first one that matches is used):
page/category/<tree_path>/content_type/<app>.<model>/<slug>/object.html
page/category/<tree_path>/content_type/<app>.<model>/object.html
page/category/<tree_path>/object.html
page/content_type/<app>.<model>/object.html
page/object.html
Parameters: - request –
HttpRequest
from Django - category –
Category.tree_path
(empty if home category) - month day (year) – date matching the publish_from field of the Publishable object
- slug – slug of the Publishable
- url_remainder – url after the object’s url, used to locate custom views in custom_urls.resolver
Raises Http404: if the URL is not valid and/or doesn’t correspond to any valid Publishable
- object:
Templatetags¶
Core templatetags¶
Core templatetags are automatically loaded for your disposal.
Tag that will obtain listing of top objects for a given category and store them in context under given name.
Usage:
{% listing <limit>[ from <offset>][of <app.model>[, <app.model>[, ...]]][ for <category> ] [with children|descendents] [using listing_handler] as <result> %}
- Parameters:
Option Description limit
Number of objects to retrieve. offset
Starting with number (1-based), starts from first if no offset specified. app.model
, ...List of allowed models, all if omitted. category
Category of the listing, all categories if not specified. Can be either string (tree path), or variable containing a Category object. children
Include items from direct subcategories. descendents
Include items from all descend subcategories. exclude
Variable including a Publishable
to omit.using
Name of Listing Handler ro use result
Store the resulting list in context under given name.
Examples:
{% listing 10 of articles.article for "home_page" as obj_list %} {% listing 10 of articles.article for category as obj_list %} {% listing 10 of articles.article for category with children as obj_list %} {% listing 10 of articles.article for category with descendents as obj_list %} {% listing 10 from 10 of articles.article as obj_list %} {% listing 10 of articles.article, photos.photo as obj_list %}
Tag Node representing our idea of a reusable box. It can handle multiple parameters in its body which will then be accessible via
{{ box.params }}
in the template being rendered.Note
The inside of the box will be rendered only when redering the box in current context and the
object
template variable will be present and set to the target of the box.Author of any
Model
can specify it’s ownbox_class
which enables custom handling of some content types (boxes for polls for example need some extra information to render properly).Boxes, same as core-views, look for most specific template for a given object an only fall back to more generic template if the more specific one doesn’t exist. The list of templates it looks for:
box/category/<tree_path>/content_type/<app>.<model>/<slug>/<box_name>.html
box/category/<tree_path>/content_type/<app>.<model>/<box_name>.html
box/category/<tree_path>/content_type/<app>.<model>/box.html
box/content_type/<app>.<model>/<slug>/<box_name>.html
box/content_type/<app>.<model>/<box_name>.html
box/content_type/<app>.<model>/box.html
box/<box_name>.html
box/box.html
Note
Since boxes work for all models (and not just
Publishable
subclasses), some template names don’t exist for some model classes, for examplePhoto
model doesn’t have a link toCategory
so that cannot be used.Boxes are always rendered in current context with added variables:
object
- object being representedbox
- instance ofella.core.box.Box
Usage:
{% box <boxtype> for <app.model> with <field> <value> %} param_name: value param_name_2: {{ some_var }} {% endbox %} {% box <boxtype> for <var_name> %} ... {% endbox %}
Parameters:
Option Description boxtype
Name of the box to use app.model
Model class to use field
Field on which to do DB lookup value
Value for DB lookup var_name
Template variable to get the instance from Examples:
{% box home_listing for articles.article with slug "some-slug" %}{% endbox %} {% box home_listing for articles.article with pk object_id %} template_name : {{object.get_box_template}} {% endbox %} {% box home_listing for article %}{% endbox %}
Renders a rich-text field using defined markup.
Example:
{% render some_var %}
blurs IP address
Obfuscates e-mail addresses - only @ and dot
Custom URLs templatetags¶
Lot of what you see here has been stolen from Django’s {% url %}
tag.
Get URL using Ella custom URL resolver and return it or save it in context variable.
Syntax:
{% custom_url <FOR_VARIABLE> <VIEWNAME>[[[ <ARGS>] <KWARGS>] as <VAR>] %}
Examples:
{% custom_url object send_by_email %} {% custom_url object send_by_email 1 %} {% custom_url object send_by_email pk=1 %} {% custom_url object send_by_email pk=1 as saved_url %}
Pagination¶
When using any of these, you need to call {% load pagination %}
prior to doing it.
Renders a
inclusion_tags/paginator.html
orinc/paginator.html
template with additional pagination context. To be used in conjunction with theobject_list
generic view.If
TEMPLATE_NAME
parameter is given,inclusion_tags/paginator_TEMPLATE_NAME.html
orinc/paginator_TEMPLATE_NAME.html
will be used instead.Adds pagination context variables for use in displaying first, adjacent pages and last page links in addition to those created by the
object_list
generic view.Taken from http://www.djangosnippets.org/snippets/73/
Syntax:
{% paginator [NUMBER_OF_ADJACENT_PAGES] [TEMPLATE_NAME] %}
Examples:
{% paginator %} {% paginator 5 %} {% paginator 5 "special" %} # with Django 1.4 and above you can also do: {% paginator template_name="special" %}
Photos¶
Deprecated, use {% image %} instead. Generates thumbnails for
Photo
instances.syntax:
{% img <format> for <var> as <var_name> %} {% img <format> with <field_value> as <var_name> %}
examples:
{% img category_listing for object.photo as thumb %} {% img category_listing with pk 1150 as thumb %}
Positions¶
Render a given position for category. If some position is not defined for first category, position from its parent category is used unless nofallback is specified.
Syntax:
{% position POSITION_NAME for CATEGORY [nofallback] %}{% endposition %} {% position POSITION_NAME for CATEGORY using BOX_TYPE [nofallback] %}{% endposition %}
Example usage:
{% position top_left for category %}{% endposition %}
Syntax:
{% ifposition POSITION_NAME ... for CATEGORY [nofallback] %} {% else %} {% endifposition %}
Template overview¶
This doc part is ment as quick reference for templates that Ella uses. The details on the template usage are kept in the section related to the each of the templates presented.
Object detail templates¶
This table shows the fallback used when selecting the right template for an object. Note how the most specific template is searched for first. When no such template is found, Ella tries the find second-most specific and so on.
As a criterion for selection, two things are considered:
- Object’s
ContentType
, specificallyCONTENT_TYPE_NAME
which is defined asapp_label.model_label
. path
attribute of theCategory
which object belongs to.
Path | Description |
---|---|
page/category/[PATH]/content_type/[CONTENT_TYPE_NAME]/object.html | First template to try (category and content-specific)
when rendering a Publishable detail. |
page/content_type/[CONTENT_TYPE_NAME]/object.html | Content-type specific template to try
when rendering a Publishable detail. |
page/category/[PATH]/object.html | Category-specific template to try when
rendering a Publishable detail. |
page/object.html | Fallback for rendering a Publishable detail
page such as article content, see
Object detail page. |
Category detail templates¶
Following table shows the template path prototypes used when selecting the
suitable template for a category detail. Ella tries to find
a correct template by inspecting the path
attribute of the given
Category
object.
Note
The category.html can be overriden for specific categories via administration. This will affect the mentioned fallback so that instead of category.html Ella will search for [OVERRIDEN_NAME].html where [OVERRIDEN_NAME] stands for name of the selected template.
For the details, see Category detail page.
Path | Description |
---|---|
page/category/[PATH]/category.html | Specific template for a category detail page. |
page/category.html | Fallback template for rendering a category detail page, category listings, static pages. |
Box templates¶
Box templates are distinguised only by CONTENT_TYPE_NAME
as described
above. The root for searching is in the box
subdirectory of your
templates. Also, boxes are named so that the name of the template
searched is directly related to the name of the box being rendered.
Path | Description |
---|---|
box/content_type/[CONTENT_TYPE_NAME]/[BOX_NAME].html | Content-type specific template for a box named [BOX_NAME]. |
box/[BOX_NAME].html | Named template for a box without any specific content type. These are boxes that are same for most of publishables. |
box/box.html | Fallback template for
box templatetag
when no specific template for box is found. |
Listing templates¶
Templates for listings (see Archive pages) follow same rules as categories with the only difference is that a listing.html is used as template name.
Other templates¶
Path | Description |
---|---|
inclusion_tags/paginator.html | Template for rendering pagination when
listing a category content. Used by
paginator
templatetag. |
404.html | Used to show user-friendly HTTP 404 page. |
500.html | Used to show user-friendly HTTP 500 page. |
base.html | Not required, but convention in Django apps is that this is the base layout template. |
As mentioned in Template fallback mechanisms, when finding the suitable template, Ella uses smart template fallback for category, object and box templates so that the ones listed above are only used as last resort. Please refer there for the details on how Ella decides which template to use.
Middleware¶
-
class
ella.core.middleware.
UpdateCacheMiddleware
¶ Response-phase cache middleware that updates the cache if the response is cacheable.
Must be used as part of the two-part update/fetch cache middleware. UpdateCacheMiddleware must be the first piece of middleware in MIDDLEWARE_CLASSES so that it’ll get called last during the response phase.
-
process_response
(request, response)¶ Sets the cache, if needed.
-
-
class
ella.core.middleware.
FetchFromCacheMiddleware
¶ Request-phase cache middleware that fetches a page from the cache.
Must be used as part of the two-part update/fetch cache middleware. FetchFromCacheMiddleware must be the last piece of middleware in MIDDLEWARE_CLASSES so that it’ll get called last during the request phase.
-
process_request
(request)¶ Checks whether the page is already cached and returns the cached version if available.
-
Common gotchas & FAQs¶
This section tries to present frequent problems Ella users run into. It provides solutions for those problems. Hopefully, it will enhance you understanding for doing the things Ella-way.
Category-specific sidebars¶
Sidebars to show information related to the currently active category. This can be a category-related poll, most interesting articles by editors choice or something completely different.
Answer for this question is the same as in previous question. Use positions! If you are not sure how to do it, please refer to Defining positions on the page.
Taking advantage of template inheritance¶
One of the best things about Django is undoubtedly it’s templating framework. And one of it’s most powerful features is the template inheritance. When building up Django templates, you use so-called blocks which can then be overriden in the child template which inherits from the parent template. When using Ella, it’s very beneficial to take the full advantage of the inheritance concept since the number of templates in large Ella websites can grow up significantly. Using the inheritance, you can very effectively write as little code as possible. Here are some hints you may found useful:
Always write the base template for object and category detail pages. Try to put there as much shared code as possible.
In you base template, don’t hesitate to define many blocks so the child templates won’t need to override big pieces of code.
It often make sense to put almost all parts of the base template into blocks. This applies for titles, descriptions, perexes, comment sections, object tools and so on. The more you allow to override, the smaller the child template will be.
When dealing with content used in more than one template type or when it’s hard to keep the inheritance scheme for some reason, use
{% include %}
and put those pieces of content in reusable snippets in yourinclusion_tags
template subdirectory. A common use case scenario for this can be a right sidebar. Consider following example of reusable right col template. First, define the baserightcol.html
template:<!-- in page/inclusion_tags/rightcol.html --> {% block rightcol_top %}{% endblock %} {% block rightcol_top_articles %} ... code showing top articles .. {% endblock %} {% block rightcol_category_poll %} ... code showing poll related to the category ... {% endblock %} {% block rightcol_bottom %}{% endblock %}
This template contains the the stuff a sidebar can contain with possibility to add your own stuff to the top and to the bottom of it. Next define child templates of the
rightcol.html
for homepage and common category:<!-- in page/inclusion_tags/rightcol_hp.html --> {% extends "page/inclusion_tags/rightcol.html" %} {% block rightcol_top %} ... some special code to add on top of the right col ... {% endblock %} <!-- in page/inclusion_tags/rightcol_category.html --> {% extends "page/inclusion_tags/rightcol.html" %} {% block rightcol_top_articles %}{% endblock %}
For the purpose of this example, we added a special piece of code at the top of the sidebar in homepage and turned off the displaying of top articles in common categories. In real-world situation, your intents will be probably little different, but for the need of demonstration, this is sufficent. Finally, put following piece of code in your base
category.html
:<!-- in page/category.html --> {% block rightcol %} <div id="sidebar"> {% block rightcol_content %} {% if is_homepage %} {% include "inc/rightcol_hp.html" %} {% else %} {% include "inc/rightcol_category.html" %} {% endif %} {% endblock %} </div> {% endblock %}
In the main category template, we can easily implement a default behavior without need to duplicate a single line of code.
Every time you find yourself duplicating a HTML code, try to think if some kind of inheritance wouldn’t help you avoid doing so. In most cases, this would be true.
Static pages that don’t ever change¶
Content-heavy websites usually don’t build it’s success on lot of static pages. However, there are always some a Ella is ready to provide effective weapons to get rid of them.
The key here is to use Category
and define a custom template, e.g.
staticpage.html
to use when you need to use the category as static page.
The reasoning for this is that categories already have nice, SEO-friendly URLs
and it would simply be unnecessary overhead to create a special solution for
this. You can put you content to Category.content
field which was added
for that purpose. Then simply use something like this:
<!-- in page/staticpage.html -->
{% extends "page/base.html" %}
{% block content %}
<h1>{{ category }}</h1>
{% render category.content %}
{% endblock %}
Integrating searching¶
TODO: create ella-haystack and be done with it.
List of configuration settings¶
Core settings¶
- CACHE_TIMEOUT
Timeout used for cache persistence for most of cached function Ella uses.
Default:
600
- CACHE_TIMEOUT_LONG
Chache persistence timeout for rarely-changing results.
Default:
3600
- CATEGORY_LISTINGS_PAGINATE_BY
Number of objects per page when browsing the category listing.
Default:
20
- RSS_NUM_IN_FEED
Number of items in automated category RSS/Atom feeds.
Default:
10
- RSS_ENCLOSURE_PHOTO_FORMAT
Photo format to use when providing photo link in RSS/Atom feed
<enclosure>
element.Default:
None
- DOUBLE_RENDER
Boolean that switches the Double render function, for more details on Double rendering, see Double rendering.
Default:
False
- DOUBLE_RENDER_EXCLUDE_URLS
URLs to be excluded from double rendering. For details, see Double rendering.
Default:
None
- RELATED_FINDERS
List of named related finders. For instructions how to use it, see Working with related objects.
Default:
RELATED_FINDERS = { 'default': ( 'ella.core.related_finders.directly_related', 'ella.core.related_finders.related_by_category', ), 'directly': ( 'ella.core.related_finders.directly_related', ) }
Photos settings¶
- PHOTOS_FORMAT_QUALITY_DEFAULT
Sampling quality choices to use in administration when defining
photo formats
.Default:
PHOTOS_FORMAT_QUALITY = ( (45, _('Low')), (65, _('Medium')), (75, _('Good')), (85, _('Better')), (95, _('High')), )
- PHOTOS_CUSTOM_SUBDIR
Custom subdirectory in
photos
directory where to place the photos.Default:
''
- PHOTOS_UPLOAD_TO
Completely override where the photos are uploaded to. Symbols
%Y
,%m
and%d
are replaced by integer value of year, month and day respectively.Default:
'photos/%Y/%m/%d'
Sites using Ella¶
Ella is getting more and more popular. Here are some sites that take advantage of it:
Community¶
- Mailing list: ella-project@googlegroups.com
- IRC channel: #ellacms@freenode.net
License¶
Ella is licensed under the BSD licence. It utilizes many conceps and examples from django itself, djangosnippets and several other open-source project. We would like to thank the community around Django for the huge amount of great quality code they share with other Djangonauts. We are proud to be part of that community and hope that somebody will find this project helpfull.