> On May 6, 2018, at 14:27, Jonathan Vanasco <[email protected]> wrote:
> 
> I'm doing some housekeeping on an app that has been a bit too lax on keeping 
> to it's own coding standards.  
> 
> There have been a bunch of updates over the past few years to the views 
> systems, so I'm hoping something may work for our needs...
> 
> In a handful of sections, it utilize class based views that rely on 
> inheritance for setup routines.
> 
> for example...
> 
> 
>      class Foo(object):
>            def __init__(self, request):
>                 self.request = request
>                 ... common setup ...
> 
>            @view_config(route_name="bar",)
>            def bar(self):
>                  pass
> 
> I was wondering if it is possible to hook into pyramid after the Foo() is 
> instantiated, but before `Foo.bar` is called.
> 
> What I want to accomplish, in case someone has a better suggestion:
> 
> * The views i'm dealing with generally handle form processing on an API.  
> * There are a handful of common setup and form validation routines that 
> happen on these
> * I'd like to define and trigger the common validation in a parent class, to 
> ensure it runs. a handful of views were not calling the correct validation 
> routines, because people make easy mistakes like that.

Create a view deriver that is used to do the processing before entering the 
view, allowing you to pass a validation routine to the @view_config instance 
that validates? Have it raise at config time if there is no validation routine 
defined for that view?

> * I could integrate this processing into __init__, but error reporting would 
> be much easier if it occurs after __init__, so I can utilize the class 
> instance.

If you want to do this you'd have to replace the default view mapper to do the 
extra work here:

https://github.com/Pylons/pyramid/blob/master/pyramid/viewderivers.py#L114-L139 
<https://github.com/Pylons/pyramid/blob/master/pyramid/viewderivers.py#L114-L139>

This deals with instantiating the class and calling the view (either the view 
attribute or __call__ on the instantiated class). I'd recommend going with a 
view deriver...

> 
> 
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "pylons-discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to [email protected] 
> <mailto:[email protected]>.
> To post to this group, send email to [email protected] 
> <mailto:[email protected]>.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/pylons-discuss/ee79f36e-f7f1-4f75-abb3-d4e31ca879f0%40googlegroups.com
>  
> <https://groups.google.com/d/msgid/pylons-discuss/ee79f36e-f7f1-4f75-abb3-d4e31ca879f0%40googlegroups.com?utm_medium=email&utm_source=footer>.
> For more options, visit https://groups.google.com/d/optout 
> <https://groups.google.com/d/optout>.


For example:

import logging

from pyramid.path import DottedNameResolver

from marshmallow import Schema

>From . import ValidationFailure

log = logging.getLogger(__name__)

# request.cstruct validation

def validation_view(view, info):
    if info.options.get('validator'):
        name_resolver = DottedNameResolver(info.package)
        validator = name_resolver.maybe_resolve(info.options.get('validator'))

        # If the validator is a subclass of Schema, we assume we need to create
        # it and that it has a load function that returns a tuple of
        # data/errors
        if issubclass(validator, Schema):
            def wrapped_validator(jstruct):
                (data, errors) = validator().load(jstruct)

                # The validator should probably raise by itself...
                if errors:
                    log.debug(errors)
                    raise ValidationFailure(errors)

                return data

            validator_func = wrapped_validator
        else:
            validator_func = validator

        def wrapper_view(context, request):
            try:
                jstruct = request.json_body
            except ValueError as e:
                log.debug(e)
                raise HTTPBadRequest({'error': 'Expecting JSON. Didn\'t work 
out.'})

            if jstruct:
                request.appstruct = validator_func(jstruct)

            return view(context, request)
        return wrapper_view
    return view

validation_view.options = ('validator',)

Add it to your config:

    # Add the validator view deriver
    config.add_view_deriver('.validation.validation_view')

And here is a sample view:

    @view_config(
        name='forgot',
        request_method='POST',
        validator='myproject.validation.user.Email',
    )
    def forgot(self):
        request = self.request
        dbsession = request.dbsession
        appstruct = request.appstruct

        user = dbsession.query(m.User)\
            .filter(m.User.email == appstruct['email'])\
            .one_or_none()

        if user is not None:
            request.notify(e.UserForgotPassword(request, user))

        return HTTPNoContent()

In my case I also allow you to pass a function that validates the input instead 
of a Marshmallow schema, but the schema works really well for most of my API 
endpoints. You could off course replace it with Colander or any other validator.

Currently the view deriver just returns the normal view if there is no 
validator specified, but you could also raise a ConfigError or something 
similar, you may also require multiple options so you can for example turn off 
validation for a particular view.

Do note that ValidationFailure takes the marshmallow errors/or your validation 
function's output and I have a special view that handles ValidationFailures by 
turning them into HTTPBadRequest's with extra information on what part of the 
validation failed/why.

Anyway, you get the basic gist of it and hopefully this helps you find a 
solution to your problem.

Bert JW Regeer

-- 
You received this message because you are subscribed to the Google Groups 
"pylons-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/pylons-discuss/DC8B90FA-EDE8-4A72-B272-F114758E34BA%400x58.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to