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)
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):
....
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With