Basically you have to extend the existing content type shipped with Kotti and add your custom fields.
But let's suppose you need a new content type named ImageWithLink with the following fields:
- title
- description
- image
- link
resources.py
from zope.interface import implementsThe code is quite self-explaining: you create a new ImageWithLink class that inherits from Image. You only need to add your custom field named link and you initialize the link in the __init__ code after calling the super method.
from kotti.resources import Image
from kotti.interfaces import IImage
from sqlalchemy import Column
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy import Unicode
class ImageWithLink(Image):
implements(IImage)
id = Column(Integer, ForeignKey('images.id'), primary_key=True)
link = Column(Unicode(1000))
type_info = Image.type_info.copy(
name=u'ImageWithLink',
title=u'ImageWithLink',
add_view=u'add_image_link',
addable_to=['Document'],
)
def __init__(self, link=u"", **kwargs):
super(ImageWithLink, self).__init__(**kwargs)
self.link = link
views/content.py
import colanderHere the code is more complex. There is a dynamic schema definition with the Kotti's temp store implementation. Both the add and the edit form refer to this schema, with some overrides because our object does not behave like files or images.
from deform import FileData
from deform.widget import FileUploadWidget
from kotti.views.edit import ContentSchema
from kotti.views.edit.content import ImageEditForm
from kotti.views.edit.content import ImageAddForm
from kotti.views.form import validate_file_size_limit
from kotti.views.form import FileUploadTempStore
from kotti.views.form import AddFormView
from pyramid.view import view_config
from kotti_yourplugin import _
from kotti_yourplugin.resources import ImageWithLink
from kotti_yourplugin.validators import link_validator
def ImageWithLinkSchema(tmpstore):
""" File schema with no set title missing binding """
class ImageWithLinkSchema(ContentSchema):
file = colander.SchemaNode(
FileData(),
title=_(u'File'),
widget=FileUploadWidget(tmpstore),
validator=validate_file_size_limit,
)
link = colander.SchemaNode(
colander.String(),
title=_('Link'),
validator=link_validator,
missing=u'',
)
def after_bind(node, kw):
del node['tags']
return ImageWithLinkSchema(after_bind=after_bind)
@view_config(name='edit', permission='edit',
renderer='kotti:templates/edit/node.pt')
class ImageWithLinkEditForm(ImageEditForm):
def schema_factory(self):
tmpstore = FileUploadTempStore(self.request)
return ImageWithLinkSchema(tmpstore)
@view_config(name=ImageWithLink.type_info.add_view, permission='add',
renderer='kotti:templates/edit/node.pt')
class ImageWithLinkAddForm(ImageAddForm):
item_type = _(u"Banner Box")
item_class = ImageWithLink
def schema_factory(self):
tmpstore = FileUploadTempStore(self.request)
return ImageWithLinkSchema(tmpstore)
def save_success(self, appstruct):
# override this method (no filename as title
# like images)
return AddFormView.save_success(self, appstruct)
def add(self, **appstruct):
# override (no tags in our form)
buf = appstruct['file']['fp'].read()
filename = appstruct['file']['filename']
return self.item_class(
title=appstruct['title'] or filename,
description=appstruct['description'],
data=buf,
filename=filename,
mimetype=appstruct['file']['mimetype'],
size=len(buf),
)
validators.py
UPDATE 20150211: no need to write this validator. Use the url validator provided by colander instead (colander.url). Anyway you can use all the builtin colander validators or write your own validators.
import reHere you can see an example of link validator based on a regular expression. This validator decorates our link field of the ImageWithLink schema.
import colander
from kotti_yourplugin import _
VALID_PROTOCOLS = ('http',)
URL_REGEXP = r'(%s)s?://[^\s\r\n]+' % '|'.join(VALID_PROTOCOLS)
def link_validator(node, value):
""" Raise a colander.Invalid exception if the provided url
is not valid
"""
def raise_invalid_url(node, value):
raise colander.Invalid(
node, _(u"You must provide a valid url."))
if value:
if not re.match(URL_REGEXP, value):
raise_invalid_url(node, value)
Obviously you need to add in your kotti_configure method your ImageWithLink in the kotti.available_types settings.
__init__.py
def kotti_configure(settings):
settings['pyramid.includes'] += ' kotti_yourplugin'
settings['kotti.available_types'] += ' kotti_yourplugin.resources.ImageWithLink'
and enable your configurator in your .ini file:
kotti.configurators = mip_course.kotti_configure
And what about the default view of your content types? If you visit an ImageWithLink box it will behave like an image: it inherits the default view of the image (you should customize it adding the link on the image, very simple: not showed in this blog post), no need to deal with the image resize machinery, etc.
As you can see, Kotti is a flexible solution if you need a simple but powerful CMS solution based on Python, Pyramid and SQLAlchemy. You may consider it as a simple framework (but easy to understand, don't be scared by the word framework. It is really developer friendly). If you are curious about how to manage contents with Kotti you may play with the demo online: http://kottidemo.danielnouri.org/ (admin - qwerty).
All posts about Kotti
- Pyramid, MySQL and Windows: the good, the ugly and the bad
- Kotti CMS events - insert subobject automatically
- Kotti CMS - how to turn your Kotti CMS into an intranet
- Kotti CMS - how to store arbitrary data with annotations
- How to install Kotti CMS on Windows
- Kotti CMS - avoid types addable in content root
- Kotti CMS - how to create a new content type with an image
- Kotti CMS - workflow reference
No comments:
Post a Comment
Note: only a member of this blog may post a comment.