Configuring Ziggurat Foundations

Installation and initial migration

Install the package:

$ pip install ziggurat_foundations

Now it’s time to initialize your model structure with alembic.

You will first need to install alembic:

$ pip install alembic>=0.7.0

After you obtain recent alembic you can now run your migrations against database of your choice.


It is critical that you use alembic for migrations, if you perform normal table creation like metadata.create_all() with sqlalchemy you will not be able to perform migrations if database schema changes for ziggurat and some constraints will be missing from your database even if things will appear to work fine for you.

First you will need to create alembic.ini file with following contents:

script_location = ziggurat_foundations:migrations
sqlalchemy.url = driver://user:pass@host/dbname

keys = root,sqlalchemy,alembic

keys = console

keys = generic

level = WARN
handlers = console
qualname =

level = WARN
handlers =
qualname = sqlalchemy.engine

level = INFO
handlers =
qualname = alembic

class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S

then you can run migration command:

$ alembic upgrade head

At this point all your database structure should be prepared for usage.

Implementing ziggurat_foundations within your application


class names like User inside ziggurat_foundations.models namespace CAN NOT be changed because they are reused in various queries - unless you reimplement ziggurat_model_init

We need to include ALL mixins inside our application and map classes together so internal methods can function properly.

In order to use the mixins inside your application, you need to include the follwing code inside your models file, to extend your existing models (if following the basic pyramid tutorial):

# ... your DBSession and base gets created in your favourite framework ...

import ziggurat_foundations.models
from ziggurat_foundations.models.base import BaseModel
from ziggurat_foundations.models.external_identity import ExternalIdentityMixin
from import GroupMixin
from ziggurat_foundations.models.group_permission import GroupPermissionMixin
from ziggurat_foundations.models.group_resource_permission import GroupResourcePermissionMixin
from ziggurat_foundations.models.resource import ResourceMixin
from ziggurat_foundations.models.user import UserMixin
from ziggurat_foundations.models.user_group import UserGroupMixin
from ziggurat_foundations.models.user_permission import UserPermissionMixin
from ziggurat_foundations.models.user_resource_permission import UserResourcePermissionMixin
from ziggurat_foundations import ziggurat_model_init

# this is needed for scoped session approach like in pylons 1.0
ziggurat_foundations.models.DBSession = DBSession
# optional for folks who pass request.db to model methods

# Base is sqlalchemy's Base = declarative_base() from your project
class Group(GroupMixin, Base):

class GroupPermission(GroupPermissionMixin, Base):

class UserGroup(UserGroupMixin, Base):

class GroupResourcePermission(GroupResourcePermissionMixin, Base):

class Resource(ResourceMixin, Base):
    # ... your own properties....

    # example implementation of ACLS for pyramid application
    def __acl__(self):
        acls = []

        if self.owner_user_id:
            acls.extend([(Allow, self.owner_user_id, ALL_PERMISSIONS,), ])

        if self.owner_group_id:
            acls.extend([(Allow, "group:%s" % self.owner_group_id,
                          ALL_PERMISSIONS,), ])
        return acls

class UserPermission(UserPermissionMixin, Base):

class UserResourcePermission(UserResourcePermissionMixin, Base):

class User(UserMixin, Base):
    # ... your own properties....

class ExternalIdentity(ExternalIdentityMixin, Base):

# you can define multiple resource derived models to build a complex
# application like CMS, forum or other permission based solution

class Entry(Resource):
    Resource of `entry` type

    __tablename__ = 'entries'
    __mapper_args__ = {'polymorphic_identity': 'entry'}

    resource_id = sa.Column(sa.Integer(),
                                          ondelete='CASCADE', ),
                            primary_key=True, )
    # ... your own properties....
    some_property = sa.Column(sa.UnicodeText())

ziggurat_model_init(User, Group, UserGroup, GroupPermission, UserPermission,
               UserResourcePermission, GroupResourcePermission, Resource,
               ExternalIdentity, passwordmanager=None)


Default password manager will use pbkdf2_sha256, but if you want different configuration pass passlib compatible password manager to ziggurat_model_init.