#! /usr/bin/env python
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# Copyright © 2015 uralbash <root@uralbash.ru>
#
# Distributed under terms of the MIT license.
"""
Provide SQLAlchemy resource for pyramid_sacrud.
"""
from zope.interface import implementer
from zope.sqlalchemy import ZopeTransactionExtension
from pyramid.location import lineage
from pyramid.threadlocal import get_current_registry
import sqlalchemy
from sacrud.action import CRUD
from sacrud.common import pk_to_list, pk_list_to_dict, get_attrname_by_colname
from sacrud_deform import SacrudForm
from sqlalchemy.orm import sessionmaker, scoped_session
from pyramid_sacrud.interfaces import ISacrudResource
[docs]class BaseResource(object):
breadcrumb = True
def __init__(
self, table, dbsession=None, name=None, **kwargs
):
self.table = table
self.kwargs = kwargs
self._dbsession = dbsession
self.__name__ = name or getattr(self, '__name__', None)
@property
def verbose_name(self):
return getattr(self.table, 'verbose_name', self.table.__tablename__)
@property
def _columns(self):
columns = getattr(self.table, 'sacrud_list_col',
self.table.__table__.c)
class Column(object):
def __init__(self, column):
self.column = column
def value(self, row):
return getattr(
row,
get_attrname_by_colname(row, self.column.name)
)
@property
def name(self):
return getattr(self.column.info, 'verbose_name',
self.column.name)
return list(Column(col) for col in columns)
@classmethod
def _get_id(cls, obj, json=True):
return pk_to_list(obj, json)
@property
def ps_crud(self):
update = self.get_update_resource
delete = self.get_delete_resource
create = self.get_create_resource()
mass_action = self.get_mass_action_resource()
return {
"get_id": self._get_id,
"columns": self._columns,
"crud": {
"mass_action": mass_action,
"create": create,
"update": update,
"delete": delete,
}
}
@property
def dbsession(self):
if not self._dbsession:
self._dbsession = self._default_dbsession
return self._dbsession
@dbsession.setter
def dbsession(self, dbsession):
self._dbsession = dbsession
@property
def _default_dbsession(self):
registry = get_current_registry()
engine = sqlalchemy.engine_from_config(registry.settings)
session = scoped_session(
sessionmaker(extension=ZopeTransactionExtension())
)
session.configure(bind=engine)
return session
@property
def sacrud(self):
return CRUD(self.dbsession, self.table, commit=False)
[docs] def get_mass_action_resource(self):
resource = MassActionResource(self.table, self.dbsession)
resource.__parent__ = self
return resource
[docs] def get_list_resource(self, resource):
for context in lineage(resource):
if isinstance(context, ListResource):
return context
[docs] def get_create_resource(self):
resource = CreateResource(self.table, self.dbsession)
resource.__parent__ = self
return resource
[docs] def get_update_resource(self, obj=None):
resource = UpdateResource(self.table, dbsession=self.dbsession)
resource.__parent__ = self
if obj:
pk = pk_to_list(obj)
for key in pk:
resource = resource[str(key)]
return resource
[docs] def get_delete_resource(self, obj=None):
resource = DeleteResource(self.table, dbsession=self.dbsession)
resource.__parent__ = self.get_list_resource(self)
if obj:
pk = pk_to_list(obj)
for key in pk:
resource = resource[str(key)]
return resource
@implementer(ISacrudResource)
[docs]class ListResource(BaseResource):
title = 'Alchemy view'
renderer = '/ps_alchemy/crud/list.jinja2'
def __init__(self, table, dbsession=None):
self.__name__ = table.__tablename__
super(ListResource, self).__init__(
table, dbsession=dbsession
)
@property
def items_per_page(self):
return int(
get_current_registry().settings.get(
'ps_alchemy.items_per_page', 5
)
)
def __getitem__(self, name):
if name == 'create':
return self.get_create_resource()
elif name == 'update':
return self.get_update_resource()
elif name == 'delete':
return self.get_delete_resource()
elif name == 'mass_action':
return self.get_mass_action_resource()
[docs]class CreateResource(BaseResource):
_obj = None
_form = None
title = 'Alchemy create'
__name__ = 'create'
renderer = '/ps_alchemy/crud/create.jinja2'
@property
def obj(self):
return self._obj
@obj.setter
def obj(self, obj):
self._obj = obj
self.form = SacrudForm(
obj=self._obj, dbsession=self.dbsession, table=self.table
)
@property
def form(self):
return self._form or SacrudForm(
obj=self._obj, dbsession=self.dbsession, table=self.table
)
@form.setter
def form(self, form):
self._form = form
[docs]class PrimaryKeyResource(BaseResource):
breadcrumb = False
[docs] def get_primary_key(self):
return list(reversed([
x.__name__ for x in lineage(self)
if isinstance(x, PrimaryKeyResource) and
x.__name__ not in ['update', 'delete']
]))
def _getitem(self, resource, name):
primary_key = self.get_primary_key()
primary_key.append(name)
pk_len = len(self.table.__table__.primary_key) * 2
if len(primary_key) < pk_len:
resource = self.__class__(self.table, self.dbsession, name)
resource.__parent__ = self
return resource
elif len(primary_key) == pk_len:
try:
obj = self.sacrud.read(pk_list_to_dict(primary_key)).one()
except sqlalchemy.orm.exc.NoResultFound:
return None
resource.obj = obj
resource.__parent__ = self
return resource
[docs]class UpdateResource(PrimaryKeyResource):
__name__ = 'update'
def __getitem__(self, name):
resource = CreateResource(self.table, self.dbsession, name)
return self._getitem(resource, name)
[docs]class DeleteResource(PrimaryKeyResource):
__name__ = 'delete'
def __getitem__(self, name):
resource = DeleteResource(self.table, self.dbsession, name)
return self._getitem(resource, name)
[docs]class MassActionResource(BaseResource):
__name__ = 'mass_action'