Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a view configured for superclass be used if a view for a class was configured in Pyramid?

I am creating a simple pyramid-based CMS that uses traversal. There is a class called Collection, that has some subclasses like NewsCollection, GalleriesCollection etc.

I need two kinds of views to display these collections. The frontent, html view and the backend, json view (the admin panel uses dgrid to display data). The backend view can be generic - it dumps json data in every case. The frontend view shouldn't - there will be a custom template for every kind of data.

The problem is: when I configure view like this:

@view_config(context=Collection, xhr=True, renderer='json', accept='application/json')

it works correctly. However as soon as I add any view configured for NewsCollection this one takes precedence. Even if I put predicates specifically to conflict with the above configuration (e.g. accept='text/html'), still the above view won't be called. Instead I will get a 'predicate mismatch'.

My question is - can I do anything to make the view configured for Collection be called when there are also views for NewsCollection? Or do I have to use other design (like url dispatch or adding the same view several time for different resource types)

like image 927
zefciu Avatar asked Feb 14 '13 09:02

zefciu


1 Answers

I've tried to build a very similar system and discovered the same problem - in fact, here's the ticket in Pyramid bug tracker: https://github.com/Pylons/pyramid/issues/409

In short, not all view predicates in Pyramid are equal - context is a special case. A view is first matched using context and then the selection is narrowed down using other predicates.

There's also a recent pull request which would makes Pyramid to behave the way you (and I) would expect - however, from the discussion there I see that it's not very likely to be adopted because of possible performance tradeoffs.

(UPDATE: the pull request has been merged in March 2013, so I guess it should be available the the release following 1.4)

A work-around is to use a custom predicate:

def context_implements(*types):
    """
    A custom predicate to implement matching views to resources which
    implement more than one interface - in this situation Pyramid has
    trouble matching views to the second registered interface. See
    https://github.com/Pylons/pyramid/issues/409#issuecomment-3578518

    Accepts a list of interfaces - if ANY of them are implemented the function
    returns True
    """
    def inner(context, request):
        for typ in types:
            if typ.providedBy(context):
                return True
        return False
    return inner


@view_config(context=ICollection,
    custom_predicates=(context_implements(INewsCollection),)
    )
def news_collection_view(context, request):
    ....
like image 156
Sergey Avatar answered Sep 28 '22 16:09

Sergey