Hello,

I'm trying to make use of the new-in-1.1 "accept" view predicate to register several views with the same name for the same context object to render a response in the content-type requested by the user but the result is not quite what I expect. The zcml looks like this:


 <view
    for="sigym.propag.interfaces.IPropagator"
    permission="view"
    request_method="GET"
    accept="text/html"
    renderer="sigym.ogcserver:views/templates/index.html"
    />
 <view
    for="sigym.propag.interfaces.IPropagator"
    view="sigym.ogcserver.views.viewpanels.config_view"
    permission="view"
    request_method="GET"
    accept="application/json+xconfig"
    renderer="json"
    />
 <view
    for="sigym.propag.interfaces.IPropagator"
    view=".views.list_propagations"
    permission="view"
    request_method="GET"
    accept="application/json"
    renderer="json"
    />

Everything works fine when I request the application/json and application/json+xconfig mimetypes with a xhr since I can control the "Accept" header, however, when a browser makes a "normal" request the result is unpredictable (in practice) since '*/* is sent in the accept header so all of the view predicates evaluate positively.

I made a quick POC patch so the best match is taken into account (attached). It modifies MultiView.__call__() so it narrows down the predicates that it will evaluate using the request.accept.best_match() method and it seems to work (all bfg tests still pass and the result is as expected when I manually test my bfg app). The patch is against the 1.1 branch in SVN.

Is this the right approach? If so I would like to finish it up with tests to reach full coverage and contribute it :)

Cheers,
Alberto
Index: repoze/bfg/view.py
===================================================================
--- repoze/bfg/view.py	(revision 7357)
+++ repoze/bfg/view.py	(working copy)
@@ -483,11 +483,17 @@
     def __init__(self, name):
         self.name = name
         self.views = []
+        self.views_for_mimes = {}
 
     def add(self, view, score):
         self.views.append((score, view))
         self.views.sort()
+        if getattr(view, '__accept__', None):
+            aviews = self.views_for_mimes.setdefault(view.__accept__, [])
+            aviews.append((score, view))
+            aviews.sort()
 
+
     def match(self, context, request):
         for score, view in self.views:
             if not hasattr(view, '__predicated__'):
@@ -508,7 +514,14 @@
         return view(context, request)
 
     def __call__(self, context, request):
-        for score, view in self.views:
+        if self.views_for_mimes:
+            best = request.accept.best_match(self.views_for_mimes.keys())
+            if not best:
+                raise NotFound(self.name)
+            views = self.views_for_mimes[best]
+        else:
+            views = self.views
+        for score, view in views:
             try:
                 return view(context, request)
             except NotFound:
@@ -702,12 +715,15 @@
     return False
 
 def derive_view(original_view, permission=None, predicates=(), attr=None,
-                renderer_name=None, wrapper_viewname=None, viewname=None):
+                renderer_name=None, wrapper_viewname=None, viewname=None,
+                accept=None):
     mapped_view = map_view(original_view, attr, renderer_name)
     owrapped_view = owrap_view(mapped_view, viewname, wrapper_viewname)
     secured_view = secure_view(owrapped_view, permission)
     debug_view = authdebug_view(secured_view, permission)
     derived_view = predicate_wrap(debug_view, predicates)
+    #TODO: decorate_view should propagate this attr too
+    derived_view.__accept__ = accept
     return derived_view
 
 def owrap_view(view, viewname, wrapper_viewname):
Index: repoze/bfg/zcml.py
===================================================================
--- repoze/bfg/zcml.py	(revision 7357)
+++ repoze/bfg/zcml.py	(working copy)
@@ -304,7 +304,7 @@
 
     def register():
         derived_view = derive_view(view, permission, predicates, attr, renderer,
-                                   wrapper, name)
+                                   wrapper, name, accept)
         r_for_ = for_
         r_request_type = request_type
         if r_for_ is None:
_______________________________________________
Repoze-dev mailing list
Repoze-dev@lists.repoze.org
http://lists.repoze.org/listinfo/repoze-dev

Reply via email to