Merge branch 'master' of github.com:do3cc/pyramid_formalchemy

This commit is contained in:
Patrick Gerken
2011-06-17 16:09:53 +02:00
8 changed files with 148 additions and 11 deletions
+27 -1
View File
@@ -53,7 +53,7 @@ Custom view, factory, forms
In the toward examples we just pass a ``package`` parameter to
:func:`~pyramid_formalchemy.configure`. By default the function will try to
load ``package.models`` ``package.models.DBSession`` and ``package.forms`` but
load ``package.models``, ``package.models.DBSession`` and ``package.forms`` but
you can override this. In this case you don't need to specify a package::
@@ -72,6 +72,32 @@ Having fun with the query_factory parameter
.. literalinclude:: ../../formalchemy_project/__init__.py
:pyobject: main
Custom views per model
----------------------
You can also register custom CRUD views per ModelListing::
config.formalchemy_model_view('admin',
model='pyramidapp.models.Foo',
context='pyramid_formalchemy.resources.ModelListing',
renderer='templates/foolisting.pt',
attr='listing',
request_method='GET',
permission='view')
and per Model::
config.formalchemy_model_view('admin',
model='pyramidapp.models.Foo',
context='pyramid_formalchemy.resources.Model',
name='',
renderer='templates/fooshow.pt',
attr='show',
request_method='GET',
permission='view')
Setting permissions
===================
+24
View File
@@ -7,6 +7,30 @@ def includeme(config):
config.add_static_view('fa_admin', 'pyramid_formalchemy:static')
config.add_directive('formalchemy_admin', 'pyramid_formalchemy.formalchemy_admin')
config.add_directive('formalchemy_model', 'pyramid_formalchemy.formalchemy_model')
config.add_directive('formalchemy_model_view', 'pyramid_formalchemy.formalchemy_model_view')
config.registry.pyramid_formalchemy_views = {}
def formalchemy_model_view(config, route_name,
model=None,
name='',
view='pyramid_formalchemy.views.ModelView',
context='pyramid_formalchemy.resources.Model', **kwargs):
"""custom model view registration"""
model = config.maybe_dotted(model)
context = config.maybe_dotted(context)
mixin_name = '%sCustom%s_%s_%s' % (model.__name__, context.__name__,
route_name, kwargs.get('request_method','GET'))
factory = type(mixin_name, (context,), {})
config.registry.pyramid_formalchemy_views[factory.__name__] = factory
kw = dict(route_name=route_name, view=view)
kw.update(kwargs)
config.add_view(context=factory,
name=name,
**kw)
def formalchemy_model(config, route_name,
factory='pyramid_formalchemy.resources.ModelListing',
+24 -4
View File
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
from pyramid.exceptions import NotFound
from sqlalchemy import exceptions as sqlalchemy_exceptions
import logging
log = logging.getLogger(__name__)
@@ -74,7 +75,14 @@ class Models(Base):
if item in ('json', 'xhr'):
self.request.format = item
return self
model = ModelListing(self.request, item)
self.request.model_name = item
model_class = self.get_model()
mixin_name = '%sCustom%s_%s_%s' % (model_class.__name__, ModelListing.__name__,
self.request.route_name, self.request.method)
mixin = type(mixin_name, (ModelListing, ), {})
factory = self.request.registry.pyramid_formalchemy_views.get(mixin.__name__, mixin)
model = factory(self.request, item)
model.__parent__ = self
if hasattr(model, '__acl__'):
# propagate permissions to parent
@@ -102,9 +110,15 @@ class ModelListing(Base):
if item in ('json', 'xhr'):
self.request.format = item
return self
if item in ('new',):
mixin_name = '%sCustom%s_%s_%s' % (self.request.model_class.__name__, Model.__name__,
self.request.route_name, self.request.method)
mixin = type(str(mixin_name), (Model, ), {})
factory = self.request.registry.pyramid_formalchemy_views.get(mixin.__name__, mixin)
try:
model = factory(self.request, item)
except NotFound:
raise KeyError()
model = Model(self.request, item)
model.__parent__ = self
return model
@@ -116,7 +130,13 @@ class Model(Base):
def __init__(self, request, name):
Base.__init__(self, request, name)
query = request.session_factory.query(request.model_class)
request.model_instance = request.query_factory(request, query, id=name)
try:
request.model_instance = request.query_factory(request, query, id=name)
except sqlalchemy_exceptions.SQLAlchemyError, exc:
log.exception(exc)
request.session_factory().rollback()
raise NotFound(request.path)
if request.model_instance is None:
raise NotFound(request.path)
request.model_id = name
+9 -5
View File
@@ -8,6 +8,7 @@ from formalchemy.fields import Field
from formalchemy import fatypes
from pyramid.renderers import get_renderer
from pyramid.response import Response
from pyramid.security import has_permission
from pyramid import httpexceptions as exc
from pyramid.exceptions import NotFound
from pyramid_formalchemy.utils import TemplateEngine
@@ -55,15 +56,17 @@ class ModelView(object):
models = {}
if isinstance(request.models, list):
for model in request.models:
key = model.__name__
models[key] = request.fa_url(key, request.format)
if has_permission('view', model, request):
key = model.__name__
models[key] = request.fa_url(key, request.format)
else:
for key, obj in request.models.__dict__.iteritems():
if not key.startswith('_'):
if Document is not None:
try:
if issubclass(obj, Document):
models[key] = request.fa_url(key, request.format)
if has_permission('view', obj, request):
models[key] = request.fa_url(key, request.format)
continue
except:
pass
@@ -73,7 +76,8 @@ class ModelView(object):
continue
if not isinstance(obj, type):
continue
models[key] = request.fa_url(key, request.format)
if has_permission('view', obj, request):
models[key] = request.fa_url(key, request.format)
if kwargs.get('json'):
return models
return self.render(models=models)
@@ -123,7 +127,7 @@ class ModelView(object):
def render_json_format(self, fs=None, **kwargs):
request = self.request
request.override_renderer = 'json'
if fs:
if fs is not None:
try:
fields = fs.jsonify()
except AttributeError:
+19
View File
@@ -22,6 +22,25 @@ def main(global_config, **settings):
# register an admin UI for a single model
config.formalchemy_model('foo', package='pyramidapp', model='pyramidapp.models.Foo')
# register custom model listing
config.formalchemy_model_view('admin',
model='pyramidapp.models.Foo',
context='pyramid_formalchemy.resources.ModelListing',
renderer='templates/foolisting.pt',
attr='listing',
request_method='GET',
permission='view')
# register custom model view
config.formalchemy_model_view('admin',
model='pyramidapp.models.Foo',
context='pyramid_formalchemy.resources.Model',
name='',
renderer='templates/fooshow.pt',
attr='show',
request_method='GET',
permission='view')
return config.make_wsgi_app()
+7 -1
View File
@@ -14,7 +14,7 @@ from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import sessionmaker
from zope.sqlalchemy import ZopeTransactionExtension
from pyramid.security import Allow, ALL_PERMISSIONS
from pyramid.security import Allow, Authenticated, ALL_PERMISSIONS
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
Base = declarative_base()
@@ -27,6 +27,12 @@ class MyModel(Base):
class Foo(Base):
__tablename__ = 'foo'
__acl__ = [
(Allow, 'admin', ALL_PERMISSIONS),
(Allow, Authenticated, 'view'),
(Allow, 'editor', 'edit'),
(Allow, 'manager', ('new', 'edit', 'delete')),
]
id = Column(Integer, primary_key=True)
bar = Column(Unicode(255))
@@ -0,0 +1,16 @@
<html metal:use-macro="main.macros['master']">
<body>
<div metal:fill-slot="main">
My Foo custom template
<div class="ui-pager" tal:content="structure pager" />
<table class="layout-grid" tal:content="structure fs.render()" />
<p>
<a class="ui-widget-header ui-widget-link ui-corner-all"
tal:attributes="href request.fa_url(request.model_name, 'new')">
<span class="ui-icon ui-icon-circle-plus"></span>
${F_('New')} ${model_name}
</a>
</p>
</div>
</body>
</html>
@@ -0,0 +1,22 @@
<html metal:use-macro="main.macros['master']">
<body>
<div metal:fill-slot="main">
Custom Foo view
<div tal:content="structure fs.render()" />
<div>
<p class="fa_field">
<a class="ui-widget-header ui-widget-link ui-widget-button ui-corner-all" href="#"
tal:attributes="href request.fa_url(request.model_name, request.model_id, 'edit')">
<input type="submit" value="${F_('Edit')}" />
</a>
<a class="ui-widget-header ui-widget-link ui-corner-all"
tal:attributes="href request.fa_url(request.model_name)">
<span class="ui-icon ui-icon-circle-arrow-w"></span>
${F_('Back')}
</a>
</p>
</div>
</div>
</body>
</html>