Overview

SACRUD main page

Pyramid CRUD interface. Provides an administration web interface for Pyramid. Unlike classic CRUD, pyramid_sacrud allows overrides and flexibility to customize your interface, similar to django.contrib.admin but uses a different backend to provide resources. New Architecture built on the resources and mechanism traversal, allows to use it in various cases.

The list of standard backends:

  • ps_alchemy - provides SQLAlchemy models.
  • ps_mongo - provides MongoDB.
  • etc..

Look how easy it is to use with Pyramid and SQLAlchemy:

from .models import (Model1, Model2, Model3,)

# add SQLAlchemy backend
config.include('ps_alchemy')

# add sacrud and project models
config.include('pyramid_sacrud')
settings = config.registry.settings
settings['pyramid_sacrud.models'] = (('Group1', [Model1, Model2]),
                                     ('Group2', [Model3]))

go to http://localhost:6543/sacrud/

Example can be found here https://github.com/sacrud/ps_alchemy/tree/master/example

Usage

Installing

GitHub

pip install git+http://github.com/sacrud/pyramid_sacrud.git

PyPi

pip install pyramid_sacrud

Source

git clone git+http://github.com/sacrud/pyramid_sacrud.git
cd pyramid_sacrud
pip install .

Develop

git clone git+http://github.com/sacrud/pyramid_sacrud.git
cd pyramid_sacrud
pip install -e .

Configuration

Initialize

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from .models import (Model1, Model2, Model3,)

# add SQLAlchemy backend
config.include('ps_alchemy')

# add pyramid_sacrud and project models
config.include('pyramid_sacrud')
settings = config.registry.settings
settings['pyramid_sacrud.models'] = (
    ('Group1', [Model1, Model2]),
    ('Group2', [Model3])
)

check it there http://localhost:6543/sacrud/

Set another prefix

config.include('pyramid_sacrud', route_prefix='admin')

now it there http://localhost:6543/admin/

Template redefinition

pyramid_sacrud use Jinja2 template renderer. Just create template file in your project templates/sacrud directory:

yourapp/
└── templates
    └── sacrud
          └── home.jinja2  <-- custom template for pyramid_sacrud home page

You can find a list of all the templates here https://github.com/sacrud/pyramid_sacrud/tree/master/pyramid_sacrud/templates/sacrud

Translate widget name

See also

For more information see Internationalization and Localization


To translate widgets on main page, you can use standard translate method for Pyramid.

from pyramid.i18n import TranslationStringFactory

_ = TranslationStringFactory('myapplication')
settings['pyramid_sacrud.models'] = (
    (_('Permissions'), (
            UserPermission,
            UserGroup,
            Group,
            GroupPermission,
            Resource,
            UserResourcePermission,
            GroupResourcePermission,
            ExternalIdentity,
        )
    ),
    (_('Users'), (User, Staff))
)

Authorization

If you use RootFactory for authorization, set PYRAMID_SACRUD_HOME permission for you accessed to pyramid_sacrud.

from pyramid_sacrud import PYRAMID_SACRUD_HOME

Examples

Map existing (Django) database with SQLAlchemy

Simple interface without resources

from pyramid.config import Configurator
from pyramid.session import SignedCookieSessionFactory


if __name__ == '__main__':
    my_session_factory = SignedCookieSessionFactory('itsaseekreet')
    config = Configurator(session_factory=my_session_factory)

    config.include('pyramid_sacrud', route_prefix='admin')

    app = config.make_wsgi_app()

    from wsgiref.simple_server import make_server
    server = make_server('0.0.0.0', 6543, app)
    server.serve_forever()

Usage

Simple admin web interface without resources.

$ cd examples/simple/
$ python main.py

and goto http://localhost:6543/admin/

_images/simple.png

Custom resource in admin interface

Usage

Simple admin web interface with custom resource ‘Bear’. It uses custom template bear.jinja2 to display resource Bear.

$ cd examples/custom_resource/
$ python main.py

and goto http://localhost:6543/admin/

_images/custom_resource.png
_images/custom_resource_panda.png

Source code

main.py
from zope.interface import implementer

from pyramid.view import view_config
from pyramid.config import Configurator
from pyramid_sacrud import PYRAMID_SACRUD_VIEW
from pyramid_sacrud.interfaces import ISacrudResource


@implementer(ISacrudResource)
class Bear(object):

    breadcrumb = True

    def __init__(self, name, url=None):
        self.name = name
        self.url = url

    @property
    def verbose_name(self):
        return self.name

    @property
    def __name__(self):
        return self.verbose_name


@view_config(
    context=Bear,
    renderer='bear.jinja2',
    route_name=PYRAMID_SACRUD_VIEW
)
def admin_bear_view(context, request):
    return {}

if __name__ == '__main__':
    config = Configurator()

    # Setting up pyramid_sacrud
    config.include('pyramid_sacrud', route_prefix='admin')
    settings = config.get_settings()
    settings['pyramid_sacrud.models'] = (
        ('Bears', [
            Bear(
                'Brown',
                'http://i.imgur.com/D5SBanK.jpg'
            ),
            Bear(
                'Panda',
                'http://i.imgur.com/uiJWAf3.jpg'
            ),
            Bear(
                'Polar',
                'http://i.imgur.com/j5SDeeH.jpg'
            )
        ]),
    )

    # Make app
    config.scan('.')
    app = config.make_wsgi_app()

    # Start app
    from wsgiref.simple_server import make_server
    server = make_server('0.0.0.0', 6543, app)
    server.serve_forever()
bear.jinja2
{% extends "sacrud/redefineme.jinja2" %}


{% block body %}
  <h1>{{ context.verbose_name }}</h1>
  <img src="{{ context.url }}" width=600px />
{% endblock %}

Docker

Usage

Simple admin web interface with CRUD operation for docker images. You can delete and view it. In example uses default crud templates from ps_crud module.

$ cd examples/docker_crud/
$ pip install -e .
$ pserve development.ini --reload

and goto http://localhost:6543/admin/

_images/docker-list.png
_images/docker-image.png

How it works

pyramid_sacrud copes with the resource technology, especially those who adhere to the principle of Pyramid traversal. In this example, we create resources, associate them with the own views, but inherit the templates from pyramid_sacrud and ps_crud. Also entry point for all resources from pyramid_sacrud settings is GroupResource.

Resources

When you pass the Docker in pyramid_sacrud settings, it automatically derives from GroupResource. Docker is a base resource and it not displayed in the Web interface, therefore it doesn’t require binding to the view.

Docker - base resource
class Docker(object):

    breadcrumb = True

    def __init__(self):
        self.cli = docker.Client(base_url='unix://var/run/docker.sock')

    @property
    def verbose_name(self):
        return self.__class__.__name__ + "'s"

    @property
    def __name__(self):
        return self.verbose_name

Image represent a list of all docker images in Web interface.

Image - represent docker image lists
class Image(Docker):

    def _get_id(self, row):
        return row['Id']

    @property
    def _columns(self):
        class Column:
            def __init__(self, name, value):
                self.name = name
                self.value = value

            def value(self, row):
                return self.value(row)
        return (
            Column("id", lambda x: x["Id"][:10]),
            Column("created",
                   lambda x: time.strftime("%D %H:%M",
                                           time.localtime(
                                               int(x["Created"])
                                           ))),
            Column("tag", lambda x: x["RepoTags"][0])
        )

    def __getitem__(self, name):

        if name == 'mass_action':
            return self.ps_crud["crud"]["mass_action"]
        elif name == 'update':
            return self.ps_crud["crud"]["update"]

    @property
    def ps_crud(self):
        mass_action = MassAction()
        mass_action.__parent__ = self
        update = UpdateFactory()
        update.__parent__ = self
        return {
            "get_id": self._get_id,
            "columns": self._columns,
            "crud": {
                "mass_action": mass_action,
                "update": update,
            }
        }

    @property
    def all(self):
        return self.cli.images()

It uses view:

View for Image resource
def admin_docker_list_view(context, request):
    """Show list of docker images."""
    return {
        'paginator': Page(
            context.all,
            url_maker=lambda p: request.path_url + "?page=%s" % p,
            page=int(request.params.get('page', 1)),
            items_per_page=6
        )
    }

With template ps_crud/list.jinja2 from extension module ps_crud.

@view_config(
    context=Image,
    renderer='ps_crud/list.jinja2',
    route_name=PYRAMID_SACRUD_VIEW
)
def admin_docker_list_view(context, request):
    """Show list of docker images."""

UpdateFactory designed to reflect a particular image.

UpdateFactory - choices image
class UpdateFactory(object):

    __name__ = "update"

    def __getitem__(self, name):
        return self.Update(name, self)

    def __call__(self, row):
        return self[row["Id"]]

    class Update(Docker):

        __name__ = None

        def get_image(self, img_id):
            for img in self.cli.images():
                if img['Id'] == img_id:
                    return img

        def __init__(self, name, parent):
            Docker.__init__(self)
            self.__name__ = name
            self.__parent__ = parent
            self.img = self.get_image(name)
            self.ps_crud = parent.__parent__.ps_crud
View for UpdateFactory resource
def admin_docker_update_view(context, request):
    from pprint import pformat
    return {'data': '<pre>' + pformat(context.img) + '</pre>'}
Templates
Added Docker logo to redefineme.jinja2 template
{% extends "sacrud/base.jinja2" %}

{% block menu_logo %}
  <img src="/static/docker.png" width="300px" />
{% endblock %}
Template for show image
{% extends "sacrud/redefineme.jinja2" %}


{% block title %} - {{ _(context.verbose_name) }}{% endblock %}


{% block body %}
  <div id="grid_view"></div>
  <h4>{{ _(context.verbose_name) }}</h4>

  <div class="bordered highlight hoverable z-depth-1">
    {{ data|safe }}
  </div>
{% endblock %}

API

Main module

Includeme of SACRUD

pyramid_sacrud.includeme(config)[source]

Common

Any helpers for Pyramid

pyramid_sacrud.common.set_jinja2_silent_none(config)[source]

if variable is None print ‘’ instead of ‘None’

Views

Views for Pyramid frontend

pyramid_sacrud.views.add_global_params(event)[source]
pyramid_sacrud.views.home_view(request)[source]

Exceptions

Exceptions for pyramid_sacrud

exception pyramid_sacrud.exceptions.SacrudException(message, status='error')[source]

Bases: exceptions.Exception

Just raise this exception

raise SacrudException('My Super Message', status='error')

status = error|warning|success

Interfaces

Resources

Resources of pyramid_sacrud

class pyramid_sacrud.resources.GroupResource(group, resources)[source]

Bases: object

Contribute

Contribute

New Architecture

Old Architecture is good, but it does not allow use tree structure of resources and has hard depency from SQLAlchemy, sacrud, sacrud_deform etc... This is not flexible solution. A new generation of pyramid_sacrud >= 0.3.0 represent just interface for any backends, like:

  • ps_alchemy - handle SQLAlchemy resourse
  • ps_peewee - handle PeeweeORM resourse
  • ps_ponyorm - handle PonyORM resourse
  • ps_djangoorm - handle Django ORM resourse
  • ps_mongodb - handle MongoDB resourse
  • and unniversal interface writing your own backends for example:
    • you can write filesystem backend which shown files in pyramid_sacrud and provide to you CRUD operations.
    • OS process backend shown process in pyramid_sacrud and allow to kill it
    • and all you can come to mind.

ziggform_* - it’s abstract modules, this is what needs to be done. I like the idea of ziggurat_form so I use such names.

_images/new_architecture.png

Old Architecture

Main page

He takes all the resources of the settings to return them to the template home.jinja2. It implemented in pyramid_sacrud.views.sa_home().

_images/home_how_it_works.png

List of rows

He takes all rows of resource, paginate it and return to template list.jinja2. It implemented in pyramid_sacrud.views.CRUD.List. For select action used sacrud and sacrud.action.CRUD.read().

_images/read_how_it_works.png

Delete row

He delete selected row and redirect to list of rows. It implemented in pyramid_sacrud.views.CRUD.Delete. For delete action used sacrud and sacrud.action.CRUD.delete().

_images/delete_how_it_works.png

Form for CREATE/DELETE action

If you send GET request it return HTML form for your module. To generate form it used sacrud_deform. sacrud_deform generate form with schema from ColanderAlchemy and widgets from deform. The main task of sacrud_deform is choose the right widgets from deform and make select widget for relationships. It implemented in pyramid_sacrud.views.CRUD.Add and used template create.jinja2.

_images/add_how_it_works.png

POST request for CREATE/DELETE action

If you send POST request it validate form and do create/update action from sacrud respectively sacrud.action.CRUD.create() and sacrud.action.CRUD.update(). It implemented in pyramid_sacrud.views.CRUD.Add.

_images/add_post_how_it_works.png

Backend contrubute

Same as contributor’s section of the documentation of Pyramid project.

Frontend contribute

For working with CSS and JavaScript you need install Node.js, npm and WebPack.

Note

If you don’t have Node.js and NPM installed, get it first.

Installing Node.js dependencies:

npm install

CSS

СSS files are located in pyramid_sacrud/static/css/. css pack in __main.css file in pyramid_sacrud/static/css/.

JavaScript

Js pack in __main.js in pyramid_sacrud/static/js/assets/.

For update each dependency in package.json, just use npm-check-updates.

$ npm install -g npm-check-updates
$ npm-check-updates -u
$ npm install

Build

webpack

For production:

webpack -p

Internationalization

To internationalize used a standard utility gettext (http://www.gnu.org/software/gettext/).
Before you begin, setup it in your system, such as:
apt-get install gettext

pyramid_sacrud has certain labels in templates like “Home”, “Create”, “Delete”, etc. If these labels appear in English on your admin panel although you specified another language, then this page is for you.

pyramid_sacrud needs your help for translation of these labels. Translation process involves the following steps:

Update translatable messages

Execute extract_messages each time a translatable message text is changed or added:

python setup.py extract_messages

or for linux:

make extract_messages

This will create or update pyramid_sacrud/locale/pyramid_sacrud.pot file, the central messages catalog used by the different translations.

Create new translation catalog

Execute init_catalog once for each new language, e.g.:

python setup.py init_catalog -l de -i pyramid_sacrud/locale/pyramid_sacrud.pot -o pyramid_sacrud/locale/de/LC_MESSAGES/pyramid_sacrud.po

This will create a file pyramid_sacrud/locale/de/LC_MESSAGES/pyramid_sacrud.po in which translations needs to be placed.

Update translation catalog

Execute update_catalog for each existing language, e.g.:

python setup.py update_catalog

or for linux:

make update_catalog

This will update file pyramid_sacrud/locale/de/LC_MESSAGES/pyramid_sacrud.po where translations of new text needs to be placed.

Compile catalogs

Execute compile_catalog for each existing language, e.g.:

python setup.py compile_catalog

or for linux:

make compile_catalog

Example

English locale by default:

Russian locale:

German locale:

See also

For more information about Internationalization and Localization read official pyramid docs http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/i18n.html

Also see basic settings in setup.cfg file (hint steal from here).

Templates

For translate use _ps function:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# Copyright © 2014 uralbash <root@uralbash.ru>
#
# Distributed under terms of the MIT license.

"""
Internationalization and Localization
"""
from pyramid.i18n import TranslationStringFactory

_ps = TranslationStringFactory('pyramid_sacrud')


def includeme(config):
    config.add_translation_dirs('pyramid_sacrud:locale/')
    config.scan('.views')

Example with Jinja2 template:

<div class="dashboard-title">{{ _ps('Dashboard') }}</div>
{{ _ps(_(crumb.name)) }}

Support and Development

To report bugs, use the issue tracker.

We welcome any contribution: suggestions, ideas, commits with new futures, bug fixes, refactoring, docs, tests, translations etc

If you have question, contact me sacrud@uralbash.ru or IRC channel #sacrud

License

The project is licensed under the MIT license.

Indices and tables

  Read the Docs
v: stable  
Versions
latest
stable
master
Free document hosting provided by Read the Docs.