Fallback "accept" in @view_config

48 views
Skip to first unread message

Mattias

unread,
Aug 14, 2012, 9:35:19 AM8/14/12
to pylons-...@googlegroups.com
I have a page that is supposed to answer with json if the caller sends "Accept: application/json" and with a html page if the accept header is anything else.

It sound like I should be able to do something like below according to the documentation but I can't get it to work.
    @view_config(route_name='overview',
                 accept='*/*',
                 renderer='overview.mak')
    @view_config(route_name='overview',
                 accept='application/json',
                 renderer='grid-data')
    def overview(self):
        return dict(grid=OverviewGrid(self.request))

If I do 
     @view_config(route_name='overview',
                 accept='*/*',
                 renderer='overview.mak')
    def overview(self):
        return dict(grid=OverviewGrid(self.request))
Pyramid/Webob, acceptparse:322 throws a exception with the message "The application should offer specific types, got */*" so it sound like the documentation is incorrect. 

I also tried 
    @view_config(route_name='overview',
                 renderer='overview.mak')
    @view_config(route_name='overview',
                 accept='application/json',
                 renderer='grid-data')
    def overview(self):
        return dict(grid=OverviewGrid(self.request))
But then the only match I get is application/json.

This almost does what I want.
    @view_config(route_name='overview',
                 accept="text/html",
                 renderer='overview.mak')
    @view_config(route_name='overview',
                 accept='application/json',
                 renderer='grid-data')
    def overview(self):
        return dict(grid=OverviewGrid(self.request))
This hits every normal webbrowser except for IE8+ which sends "Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, */*".

I have tried with both Chrome ("Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8") and IE8 ("Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, */*") and I can't get it to work.

I took a peek at the Pyramid code and at line 556 in config/views.py anything with accept == None or with a '*' in it gets added to the self.view list while anything with something else in the accept parameter gets added to the self.accepts list.

Later on when get_views gets called it creates a list using the self.accepts list in the order of the best match. Afterwards it adds the self.views list to the end of the list and returns that, the code then tries to call each view in the list until it succeeds. 

This means that as long as there is any other view_config with a accept parameter with the same route_name and if the webbrowser send '*/*' in the accept list then there is no way to have a general accept='*/*' view since '*/*' gets filtered by the code and best_match always returns the other view_config with a accept parameter.

If I change pyramid/config/views.py:559 from "if accept is None or '*' in accept:" to "if accept is None or '*' == accept:" and add a "return" in WebOb/acceptparse.py:320 then everything works as I expected it to.

Did I miss something or is there currently no way to do what I want without changing both Pyramid and WebOb?

Gael Pasgrimaud

unread,
Aug 14, 2012, 9:49:07 AM8/14/12
to pylons-...@googlegroups.com
On 14/08/2012 15:35, Mattias wrote:
> I have a page that is supposed to answer with json if the caller sends
> "Accept: application/json" and with a html page if the accept header is
> anything else.
>
> It sound like I should be able to do something like below according to
> the documentation
> <http://docs.pylonsproject.org/projects/pyramid/en/1.3-branch/api/config.html#pyramid.config.Configurator.add_view> but
What about:

@view_config(route_name='overview',
accept='application/json',
renderer='grid-data')
@view_config(route_name='overview',
renderer='overview.mak')
def overview(self):
return dict(grid=OverviewGrid(self.request))

I guess that if the first one doesn't match then the second is used.
> --
> You received this message because you are subscribed to the Google
> Groups "pylons-discuss" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/pylons-discuss/-/bKI_JlNV_04J.
> To post to this group, send email to pylons-...@googlegroups.com.
> To unsubscribe from this group, send email to
> pylons-discus...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/pylons-discuss?hl=en.

Mattias

unread,
Aug 14, 2012, 10:00:38 AM8/14/12
to pylons-...@googlegroups.com
Unfortunately WebOb matches "application/json" with the last "*/*" of the browsers accept string. I wonder if I could use @view_config(route_name="foo" accept="a") or something that always would end up as the best match of '*/*'. I will have to try that. 

Mattias

unread,
Aug 14, 2012, 10:04:52 AM8/14/12
to pylons-...@googlegroups.com
Thanks, it worked. It looks ugly but at least it works. I will have to run some test on it to see if the sort order is stable...

     @view_config(route_name='overview', 
                  accept='application/json', 
                  renderer='grid-data') 
     @view_config(route_name='overview', 
                  accept="a",

                  renderer='overview.mak') 
     def overview(self): 
         return dict(grid=OverviewGrid(self.request)) 
Reply all
Reply to author
Forward
0 new messages