Upload
alin-voinea
View
665
Download
1
Embed Size (px)
Citation preview
KOTTI 101
A short introduction to the
Web Application FrameworkKotti
IN THIS PRESENTATIONWhat is Kotti?First impressionsOverview of featuresMajor alternativesAdvantages and drawbacksKotti in the future
Started in 2011, at a Plone conferenceDevelopers with common history: PloneDeveloped in several sprintsAlready stable for many years
BSD licensed1.0.0 in January 2015current version: 1.2.0~9k downloads per monthstill small, butactive, healthy and welcoming community
CREATING AN ADDON$ bin/pip install Kotti
$ bin/pcreate -s kotti kotti_myaddonAuthor name [John Doe]:Author email [[email protected]]:Github username [Kotti]:[… lot of output …]
$ cd kotti_myaddon$ ../bin/pserve development.ini
CUSTOM CONTENT TYPE
from kotti.resources import Contentfrom sqlalchemy import *
class Document(Content):
id = Column(Integer(), ForeignKey('contents.id'), primary_key=True)
body = Column(UnicodeText())
mime_type = Column(String(30))
type_info = Content.type_info.copy(name=u'Document', title=_(u'Document'), add_view=u'add_document', addable_to=[u'Document'])
THE NODE CLASSadjacency list pattern
parentchildren
single root node => node treedictionary protocol
DICTIONARY PROTOCOLfrom kotti.resources import Documentfrom kotti.resources import get_root
>>> root = get_root()>>> root['about']<Document 2 at /about>
>>> root['doc1'] = Document(title='Foo', description='foo', body='<p>some HTML</p>')
TRAVERSALroot['a'] = Document(title='A', description='Document A')root['a']['b'] = Document(title='B', description='Document B')root['a']['b']['c'] = Document(title='C', description='Document C')
JOINED TABLE INHERITANCE
class hierarchy is broken up among dependent tableseach model class has its own tablethat table only includes attributes local to that class
POLYMORPHIC QUERIES>>> from kotti.resources import get_root>>> from kotti.resources import Node
>>> root = get_root()>>> for c in root.children:... print(type(c))<class 'kotti.resources.Document'><class 'kotti.resources.File'>
>>> print Node.query.filter(Node.title == 'My Document').one()<Document 5 at /my-document>
VIEWSSIMPLEST VIEW ATTACHED TO A CONTENT TYPE
from pyramid.view import view_config
@view_config(name='view', context=Document, permission='view', renderer='kotti:templates/view/document.pt')def document_view(context, request): return {}
TEMPLATE<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml" metal:use-macro="api.macro('kotti:templates/view/master.pt')"> <article metal:fill-slot="content" class="document-view content"> <h1>${context.title}</h1> <p class="lead">${context.description}</p> <div tal:replace="api.render_template('kotti:templates/view/tags.pt')" /> <div class="body" tal:content="structure context.body | None"> </div> </article></html>
SCHEMA DEFINITION: FORM CREATION, VALIDATIONimport colanderimport deformfrom kotti.views.edit.content import ContentSchema
class DocumentSchema(ContentSchema): body = colander.SchemaNode( colander.String(), title=_(u'Body'), widget=deform.widget.RichTextWidget(), missing=u"")
ADD / EDIT FORMSfrom kotti.resources import Documentfrom kotti.views.form import AddFormViewfrom kotti.views.form import EditFormViewfrom pyramid.view import view_config
@view_config(name=Document.type_info.add_view, permission='add', renderer='kotti:templates/edit/node.pt')class DocumentAddForm(AddFormView): schema_factory = DocumentSchema add = Document item_type = _(u"Document")
@view_config(context=Document, name='edit', permission='edit', renderer='kotti:templates/edit/node.pt')class DocumentEditForm(EditFormView): schema_factory = DocumentSchema
CONFIGURATION[app:kotti]use = egg:kottisqlalchemy.url = sqlite:///%(here)s/Kotti.dbkotti.configurators = kotti_tinymce.kotti_configure kotti_youraddon.kotti_configure[filter:fanstatic]use = egg:fanstatic#fanstatic[pipeline:main]pipeline = fanstatic kotti[server:main]use = egg:waitress#mainhost = 127.0.0.1port = 5000
probably the most advanced ORM for Pythondatabase agnostichas many nice, useful features
hybrid propertiesassociation proxiesordering list
transactions integrated to pyramid request lifecycle
COLANDER
define data schemavalidate & deserialize
HTML formsJSONXML
serialize Python structures tostringsmappingslists
a content workflow systemstates define
role / permission mappingtransitions define
from_stateto_staterequired_permission
guards
storing and serving files in web applicationsmultiple backends
local filesystemS3GridFSroll your own
integrates with SQLAlchemyfiles are handled like a plain model attributetransaction aware
USER INTERFACE
create contentedit contentdeletechange statefolder contents view for batch operations
Obviously inspired by Plone
...
workflowssecurity: roles, permissions, groups, sharing tabuser managementmulti file uploadeditors can choose which view is used on any contentitem
...
95% coverage of python codescale data from single file to replicated clusterable to use countless other pyramid extensions
KOTTI VS. PLONEPlone is source of inspirationmore similar to CMF in scopeno application server, only one global site
no local settingsno need for GenericSetupno need for most portal_* utilitiesnative SQL indexing, no need for portal_catalog
obviously no TTW development
Avoid burnout
smaller dev stacksmaller time in server startupsmaller time in testingno lengthy builds
... but if you're already a Plone developer
Zope Page Templatesslots, like viewletsZCA & .zcmlmany concepts that are similar or reimplemented
no undo or versioning, yetsmall number of Kotti extensions.smaller number of builtin featuresnot tweakable by editorsNo:
TTW content typescomposable layoutsportlet management
the core is stablepython 3 support (almost done)undo/versioning, using sqlalchemy-continuumREST api (partially) implementing JSONAPIsplit up some functionality from core
WHERE TO GO NEXTKotti documentation websitegithub.com/Kotti/kotti.git#[email protected] on IRC