documentation

This commit is contained in:
bkfox 2016-05-19 16:45:13 +02:00
parent 995efffc52
commit 54910f4df9
6 changed files with 118 additions and 11 deletions

81
cms/README.md Normal file
View File

@ -0,0 +1,81 @@
# Aircox.CMS
Simple CMS generator used in Aircox. Main features includes:
- website configuration and templating
- articles and static pages
- sections: embeddable views used to display related elements of an object
- posts related to external models:
- attributes binding, automatically updated
- personalization of view rendering, using templates or sections
- integrated admin interface if desired
- list and detail views + routing
- positioned menus using views
- comment
We aims here to automatize most common tasks and to ease website
configuration.
# Architecture
A **Website** holds all required informations to run the server instance. It
is used to register all kind of posts, routes to the views, menus, etc.
Basically, for each type of publication, the user declare the corresponding
model, the routes, the sections used for rendering, and register them using
website.register.
## Posts
**Post** is the base model for a publication. **Article** is the provided model
for articles and static pages.
**RelatedPost** is used to generate posts related to a model, the corresponding
bindings and so on. The idea is that you declare your own models using it as
parent, and give informations for bindings and so on. This is as simple as:
```python
class MyModelPost(RelatedPost):
class Relation:
model = MyModel
mapping = {
'thread': 'parent_field_name',
'title': 'name'
}
```
## Routes
Routes are used to generate the URLs of the website. We provide some of the
common routes: for the detail view of course, but also to select all posts or
by thread, date, search, tags.
It is of course possible to create your own routes.
Routes are registered to a router (FIXME: it might be possible that we remove
this later)
## Section
Sections are used to render part of a publication, for example to render a
playlist related to the diffusion of a program.
If the rendering of a publication can vary depending the related element, in
most of the cases when we render elements, we can find the same patterns: a
picture, a text, a list of URLs/related posts/other items.
In order to avoid to much code writing and the multiplication of template
files (e.g. one for each type of publication), we prefer to declare these
sections and configure them. This reduce the work, keep design coherent,
and reduce the risk of bugs and so on.
## Website
This class is used to create the website itself and regroup all the needed
informations to make it beautiful. There are different steps to create the
website, using instance of the Website class:
1. Create the Website instance with all basic information: name, tags,
description, menus and so on.
2. For each type of publication, register it using a Post model, a list of
used sections, routes, and optional parameters. The given name is used
for routing.
3. Register website's URLs to Django.
4. Change templates and css styles if needed.

View File

@ -14,6 +14,10 @@ from taggit.managers import TaggableManager
class Post (models.Model): class Post (models.Model):
"""
Base model that can be used as is if wanted. Represent a generic
publication on the website.
"""
thread_type = models.ForeignKey( thread_type = models.ForeignKey(
ContentType, ContentType,
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
@ -64,6 +68,9 @@ class Post (models.Model):
class Article (Post): class Article (Post):
"""
Represent an article or a static page on the website.
"""
static_page = models.BooleanField( static_page = models.BooleanField(
_('static page'), _('static page'),
default = False, default = False,
@ -141,12 +148,28 @@ class RelatedPostBase (models.base.ModelBase):
class RelatedPost (Post, metaclass = RelatedPostBase): class RelatedPost (Post, metaclass = RelatedPostBase):
""" """
Use this post to generate Posts that are related to an external model. An Post linked to an object of other model. This object is accessible through
extra field "related" will be generated, and some bindings are possible to the field "related".
update te related object on save if desired;
This is done through a class name Relation inside the declaration of the new It is possible to map attributes of the Post to the ones of the Related
model. Object. It is also possible to automatically update post's thread based
on the Related Object's parent if it is required.
Mapping can ensure that the Related Object will be updated when mapped
fields of the Post are updated.
To configure the Related Post, you just need to create set attributes of
the Relation sub-class.
```
class MyModelPost(RelatedPost):
class Relation:
model = MyModel
mapping = {
'thread': 'parent_field_name',
'title': 'name'
}
```
""" """
related = None related = None
@ -165,13 +188,11 @@ class RelatedPost (Post, metaclass = RelatedPostBase):
If there is a post_attr "thread", the corresponding rel_attr is used If there is a post_attr "thread", the corresponding rel_attr is used
to update the post thread to the correct Post model (in order to to update the post thread to the correct Post model (in order to
establish a parent-child relation between two models) establish a parent-child relation between two models)
* thread_model: generated by the metaclass that point to the * thread_model: generated by the metaclass, points to the RelatedPost
RelatedModel class related to the model that is the parent of model generated for the mapping.thread object.
the current related one.
""" """
model = None model = None
mapping = None # values to map { post_attr: rel_attr } mapping = None # values to map { post_attr: rel_attr }
thread = None
thread_model = None thread_model = None
def get_attribute (self, attr): def get_attribute (self, attr):

View File

@ -170,4 +170,5 @@ class SearchRoute (Route):
qs.distinct() qs.distinct()
return qs return qs
## TODO: by tag

View File

@ -67,6 +67,11 @@ class Website:
def register (self, name, model, sections = None, routes = None, def register (self, name, model, sections = None, routes = None,
list_kwargs = {}, detail_kwargs = {}): list_kwargs = {}, detail_kwargs = {}):
"""
Register a detail and list view for a given model, using
routes. Just a wrapper around register_detail and
register_list.
"""
if sections: if sections:
self.register_detail( self.register_detail(
name, model, name, model,

View File

@ -36,7 +36,6 @@ class Actions:
def skip (cl, monitor, controller, source): def skip (cl, monitor, controller, source):
source.skip() source.skip()
class LiquidControl (View): class LiquidControl (View):
template_name = 'aircox/liquidsoap/controller.html' template_name = 'aircox/liquidsoap/controller.html'

View File

@ -744,7 +744,7 @@ class Log (models.Model):
logger.info('log #%s: %s%s', logger.info('log #%s: %s%s',
str(self), str(self),
self.comment or '', self.comment or '',
'\n - {}: #{}'.format(self.related_type, self.related_id) ' -- {} #{}'.format(self.related_type, self.related_id)
if self.related_object else '' if self.related_object else ''
) )