SilverFlask¶
SilverFlask aims to be the first full-featured CMS building on top of solid foundations such as Flask, SQLAlchemy, Jinja2, WTForms and a huge number of plugins built on top of these such as SQLAlchemy-continuum, Flask-User, Flask-Login and countless others.
It wants to be an environment that offers the whole slew of power experienced developers are accustomed to while provide an easy platform for.
SilverFlask is partly named after SilverStripe, one of the best and fully-featured CMS’s around in PHP land. However, for my taste it had a few shortcomings. Of course, PHP as a programming language is multitudes less pleasant than python. And unfortunately, SilverStripe is built around a framework that is more or less made only for the CMS. I personally don’t like this tight coupling as the framework has not gotten much exposure outside of the SilverStripe CMS world. On the other hand, Flask is a very mature framework, and python is a lovely programming language.
Installation¶
Warning
SilverFlask is currently in a pre-alpha-stealth state. Don’t use it for anything serious. That said, feel free to experiment with it as much as you’d like to!
Clone repo:
git clone https://github.com/wolfv/SilverFlask
When in the virtualenv, install all necessary packages via
pip install -r requirements
Use the manage.py script to create the database (defaults to an sqlite
database.db
in the app folder:python manage.py createdb
Start the application server by entering
python manage.py runserver
Point your webbrowser to http://localhost:5000 to visit your first SilverFlask website
Login as
admin:admin
on http://localhost:5000/admin
The basic building blocks¶
SilverFlask defines a number of basic building blocks for websites.
User¶
The user model for SilverFlask is already defined and wired up with Flask-Login and Flask-User to provide the whole array of features that you would come to expect from a modern web-application.
Query the current user with from silverflask.core import current_user
A Permission model is also included to provide fine-grained access control if needed in silverflask.models.Role
.
Tutorial¶
This tutorial is trying to give a quick introduction in how to create your first website with SilverFlask.
Creating a simple page type¶
First, we will create a basic page type for our website. Therefore we need to subclass silverflask.models.SiteTree
:
from silverflask.models import SiteTree
class SimplePage(SiteTree):
db = {
"content": "UnicodeText"
}
Now you should point your browser to localhost:5000/admin/dev/build to automatically generate the necessary database entries for you.
When you open admin and check the “Add Pages” menu, you will see our SimplePage as one of the available page types. You can even start editing the page, save and publish it and it should render just fine in the default template. Note that all of this functionality comes from the SiteTree
This is because we chose the name content
for our db field, which is also
the standard name for the main content which is used in the default template.
We can also create a little script to create a new instance of this page:
from silverflask import db
sp = SimplePage()
sp.name = "What a beautiful title"
sp.content = "Interesting Content"
db.session.add(sp)
db.session.commit(sp)
This example also shows how the variables defined in db
are added to the class
namespace and are accessible through their names.
All column types from sqlalchemy are available, such as
- Integer
- Text
- String (text, but with a maximum length)
- Boolean
- Date, and DateTime
- ... (check sqla_types. for more)
Extending the page further¶
Suppose we want to add a cute little header image to the page, we can do that
easily by adding a has_one
relation to the SimplePage
. The relation
will point to the silverflask.models.ImageObject
.
from silverflask.models import SiteTree
class SimplePage(SiteTree):
db = {
"content": "UnicodeText"
}
has_one = {
"header_image": "ImageObject"
}
The necessary database columns for this relation are automatically added to the model.
Now you might wonder how to access this image – it’s easy. Relations are added to the object in the same way as the database columns. So using
s.image
Will return you the image object that is related to the SimplePage.
There are actually several interesting functions defined on the silverflask.models.ImageObject
which you can utilize e.g. in the template.
Reference¶
DataObject¶
-
class
silverflask.models.DataObject.
DataObject
¶ The DataObject class is the basic building block of any CMS Element. It is a mixin that provides three basic database columns:
Attributes:
Variables: - id – Primary key, integer id (use for joins and relationships)
- created_on – the datetime when the DataObject was created
- last_modified – the datetime when the DataObject was last modified
-
as_dict
()¶ Get object as dict. Very useful for json responses. :return: dict with all database columns
-
classmethod
get_cms_form
()¶ Build and return Form class.
If you want to define your custom CMS Object, you likely want to override the default CMS Form. E.g.:
from wtforms import fields def get_cms_form(cls): form = super().get_cms_form() form.textfield = fields.StringField("Textfield") return form
Returns: Form Class (has to be instantiated!).
SiteTree¶
-
class
silverflask.models.SiteTree.
SiteTree
¶ The SiteTree is the database model from which all pages have to inherit. It defines the parent/children relationships of the page tree. It also defines everything that’s needed to get nice URL slugs working.
Mixins¶
Silverflask defines a number of mixins that can be utilized to enhance DataObjects (and are used in the SiteTree class for example).
-
class
silverflask.mixins.OrderableMixin.
OrderableMixin
¶ A mixin that makes a DataObject sortable by adding a sort_order database field. Classes with this mixin automatically keep the sort_order in sync.
-
classmethod
check_duplicates
()¶ Check the table for duplicates and if there are duplicates reindex :return: nothing
-
init_order
()¶ Sort element to the end
-
insert_after
(index, orderable_base_class=None, index_absolute=True, query=None)¶ Inser after index variable
Parameters: - index – index (this is the sort_order variable of the element that you want to insert after!)
- orderable_base_class – baseclass (useful in certain circumstances e.g. gridfields)
Returns: nothing
-
move_after
(obj)¶ Move current DataObject after index (= sort_order) of another element
Parameters: index – obj element where to move after or sort order of other elements Returns: nothing
-
classmethod
reindex
()¶ Reindexes the table.
The sort order field can have “jumps” in it (e.g. 1, 4, 5, 8, 9) and reindex brings that back to a linearly ascending order: (1,2,3,4...)
-
classmethod
-
class
silverflask.mixins.VersionedMixin.
VersionedMixin
¶ A mixin that adds versioning support to DataObjects. It adds a new live table that saves the object on a publish operation, a new query_live operator that queries the live versions of the object and a versions relationship that saves all versions of this object (a version is automatically created on a save operation).
-
can_publish
()¶ Override this function to control who is allowed to publish pages in the CMS :return: Boolean (True if allowed to publish)
-
mark_as_published
()¶ Create a copy of the current draft to the live table and publish this DataObject (make it visible to the outside world). :return: empty
-
User¶
-
class
silverflask.models.User.
User
(username, password, email=None, is_enabled=True)¶ The base User model. Defines the following fields:
username = String, and unique, firstname, lastname = String
email = String, unique
The password is set with user.set_password(“password”), and then stored with encryption.
FileObject¶
The file objects reflect the file items uploaded through the CMS. ImageObject is an inherited class which implements common image functionality, such as cropping and resizing.
-
class
silverflask.models.FileObject.
FileObject
(file=None, location=None, folder=None)¶ Contains file information
Variables: - location – Location of the file
- name – Name of the file (usually filename without extension)
- type – Contains
-
delete_file
()¶ Delete this file also from disk.
-
url
()¶ Return the url for this file (handled by the
FileStorageBackend
-
class
silverflask.models.FileObject.
ImageObject
(file=None, location=None, folder=None)¶ A basic ImageObject, that inherits all properties from the file object and adds some functionality related to images, such as cropping and resizing, as well as caching the cropped and/or resized images.
-
resize
(width=None, height=None, mode='crop', background='white')¶ Resize image
Parameters: - width – define width in pixels
- height – height in pixels. If no height is set, it will be set to width (i.e. the result will be a square)
- mode – string, one of ‘crop’ (default), ‘pad’, ‘fit’ or ‘reshape’
- background – background color, as string (i.e. ‘blue’ or hex ‘#F0F000’). As supported by the ImageColor module of Pillow.
-
FileStorageBackend¶
The FileStorageBackend is a class that abstracts away the underlying file storage. At the moment, the only implemented backend is the LocalFileStorageBackend which implements methods to save files to the local flask installation (defaults to the /static/uploads/ folder).
Another FileStorageBackend could, for example, be an implementation for a S3 Backend (e.g. using the boto library).