HttpResponse.has_header

1,041 views
Skip to first unread message

Larry Martell

unread,
May 10, 2013, 9:52:14 AM5/10/13
to django...@googlegroups.com
Just upgraded to 1.5 and my app is failing with:

Internal Server Error:
Traceback (most recent call last):
File "/Library/Python/2.7/site-packages/django/core/handlers/base.py",
line 187, in get_response
response = middleware_method(request, response)
File "/Library/Python/2.7/site-packages/django/contrib/sessions/middleware.py",
line 26, in process_response
patch_vary_headers(response, ('Cookie',))
File "/Library/Python/2.7/site-packages/django/utils/cache.py",
line 142, in patch_vary_headers
if response.has_header('Vary'):
[error] AttributeError: 'function' object has no attribute 'has_header'

My code that is triggering this:

if report_response.has_header('Content-disposition'):

I didn't see anything in the docs that said this method was being
removed from the HttpResponse class.

Anyone know how I can fix this so I can use 1.5?

Tom Evans

unread,
May 10, 2013, 10:55:19 AM5/10/13
to django...@googlegroups.com
It hasn't. If you look at the exception message closely, you will see
that it does not say "HttpResponse object has no attribute ...", it
says "function object has no attribute ...". Somehow, this middleware
is receiving a function instead of a response object.

> Anyone know how I can fix this so I can use 1.5?
>

The full stack trace may explain more, but then again maybe not - the
exception happens in middleware processing, but the error is returning
a function instead of a HttpResponse object in the content generation
phase (ie in the view). You will probably need to look closely at each
function the request passes through on this particular request, and
work out where the bogus return value is coming from.

Cheers

Tom

Larry Martell

unread,
May 10, 2013, 11:37:37 AM5/10/13
to django...@googlegroups.com
That is the full stack trace. I have just one piece of middleware:

import re
class LastSiteUrl(object):

def is_admin_url(self, url):
if re.search('^(http:\/\/.*){0,1}\/admin\/', url) is None: return(False)
else: return(True)

def process_request(self, request):
if self.is_admin_url(request.path) and \
not self.is_admin_url(request.META['HTTP_REFERER']):
request.session['last_site_url'] = request.META['HTTP_REFERER']

I don't see how that could be causing this. What changed in 1.5 to
break this? In 1.4 I do not get this error with the same middleware.

Larry Martell

unread,
May 10, 2013, 4:13:42 PM5/10/13
to django...@googlegroups.com
I traced it all through base.py and the issue seems to be that my
views don't return a HttpResponse object. I have to go back to 1.4 and
my old code and see what it's returning there (I made a lot of changes
for direct_to_template and redirect_to). I wouldn't think an upgrade
would require so many changes :-(

Larry Martell

unread,
May 11, 2013, 9:08:16 AM5/11/13
to django...@googlegroups.com
So here's the problem. I replaced direct_to_template with
TemplateView.as_view (as I read at
https://docs.djangoproject.com/en/1.4/topics/generic-views-migration/)
but direct_to_template returned a HttpResponse object and
TemplateView.as_view does not. It then blows up at:

File "/Library/Python/2.7/site-packages/django/utils/cache.py", line
142, in patch_vary_headers
if response.has_header('Vary'):
AttributeError: 'function' object has no attribute 'has_header'

Surely others must have changed direct_to_template to TemplateView.
How do I get around this?

Masklinn

unread,
May 11, 2013, 9:30:15 AM5/11/13
to django...@googlegroups.com
as_view itself does not (and should not), since its job is to return a
view callable which will reply to requests.

TemplateView most definitely returns an HttpResponse though. More
precisely it returns a TemplateResponse which extends SimpleTemplateResponse
which extends HttpResponse:

as_view[0] returns a ``view`` function[1] which dispatches the request
to a CBV method based on the request's HTTP method[2]. That is
TemplateView.get[3] which calls render_to_response on the
TemplateResponseMixin[4]. Said render_to_response returns a new instance
of self.response_class[5], which defaults to TemplateResponse[6] which
as already noted is a subclass of HttpResponse through
SimpleTemplateResponse[7].

Are you sure you're using TemplateView correctly? Could you post your
urlconf? If you got a function is it possible that you replaced

(pattern, direct_to_template, {'template': template_name})

by

(pattern, TemplateView.as_view, {'template': template_name})

and thus got the ``view`` function[1] as a "response"?

> It then blows up at:
>
> File "/Library/Python/2.7/site-packages/django/utils/cache.py", line
> 142, in patch_vary_headers
> if response.has_header('Vary'):
> AttributeError: 'function' object has no attribute 'has_header'
>
> Surely others must have changed direct_to_template to TemplateView.
> How do I get around this?

[0] https://github.com/django/django/blob/master/django/views/generic/base.py#L46
[1] https://github.com/django/django/blob/master/django/views/generic/base.py#L61
[2] https://github.com/django/django/blob/master/django/views/generic/base.py#L83
[3] https://github.com/django/django/blob/master/django/views/generic/base.py#L152
[4] https://github.com/django/django/blob/master/django/views/generic/base.py#L118
[5] https://github.com/django/django/blob/master/django/views/generic/base.py#L127
[6] https://github.com/django/django/blob/master/django/views/generic/base.py#L115
[7] https://github.com/django/django/blob/master/django/template/response.py#L10

Larry Martell

unread,
May 11, 2013, 9:57:55 AM5/11/13
to django...@googlegroups.com
Yes, that is what I did. This is not in my urlconf. It's in a view
function. I replaced:

return direct_to_template(request, template)

by:

return TemplateView.as_view(template_name=template)

Is that not correct? Should I not be using as_view? I just tried using
TemplateView(template_name=template) and I got the same error.

Masklinn

unread,
May 11, 2013, 10:23:43 AM5/11/13
to django...@googlegroups.com
On 2013-05-11, at 15:57 , Larry Martell wrote:
>
> Yes, that is what I did. This is not in my urlconf. It's in a view
> function. I replaced:
>
> return direct_to_template(request, template)
>
> by:
>
> return TemplateView.as_view(template_name=template)
>
> Is that not correct?

Indeed not, `TemplateView.as_view(template)` is roughly equivalent to
`functools.partial(direct_to_template, template=template)`: it's only
one half of the operation, which returns a callable replying to
requests.

You need something along the lines of `TemplateView.as_view(template)(request)`

Larry Martell

unread,
May 11, 2013, 11:01:18 AM5/11/13
to django...@googlegroups.com
On Sat, May 11, 2013 at 8:23 AM, Masklinn <mask...@masklinn.net> wrote:
> On 2013-05-11, at 15:57 , Larry Martell wrote:
>>
>> Yes, that is what I did. This is not in my urlconf. It's in a view
>> function. I replaced:
>>
>> return direct_to_template(request, template)
>>
>> by:
>>
>> return TemplateView.as_view(template_name=template)
>>
>> Is that not correct?
>
> Indeed not, `TemplateView.as_view(template)` is roughly equivalent to
> `functools.partial(direct_to_template, template=template)`: it's only
> one half of the operation, which returns a callable replying to
> requests.
>
> You need something along the lines of `TemplateView.as_view(template)(request)`

I appreciate all the assistance. I tried that and got:

TypeError: as_view() takes exactly 1 argument (2 given)

Masklinn

unread,
May 11, 2013, 11:08:33 AM5/11/13
to django...@googlegroups.com
Oh yeah, you need to pass it as the keyword argument "template_name"
sorry about that. Basically take your code and add "(request)" at the
end.

If the current request is a GET obviously.

Larry Martell

unread,
May 11, 2013, 11:04:15 PM5/11/13
to django...@googlegroups.com
Thanks. That got me further along. I don't understand that syntax
though. Never see that before.

But now I'm having a NoReverseMatch issue that I don't get in 1.4.
I'll have to dig into that on Monday.

Masklinn

unread,
May 12, 2013, 3:07:07 AM5/12/13
to django...@googlegroups.com
It's nothing more than a function returning a function, both being called in sequence

Larry Martell

unread,
May 12, 2013, 6:13:11 PM5/12/13
to django...@googlegroups.com
Very cool. Never seen that before in python.

Larry Martell

unread,
May 12, 2013, 6:17:00 PM5/12/13
to django...@googlegroups.com
Being OCD I couldn't wait until Monday ;-) The issue was that when I
was using direct_to_template I was passing in extra_context. You can't
do that with TemplateView. I had to subclass TemplateView and provide
my own get_context_data method. Now all I have to do is change the 52
usages of {% url ... %} to quote the first argument.

Larry Martell

unread,
May 14, 2013, 9:32:41 AM5/14/13
to django...@googlegroups.com
What would I do for a POST? I have a button that is tied to a form
that is POSTed. In 1.4 the view returned:

return direct_to_template(request, template)

and that worked fine. In 1.5 I've changed it to:

return TemplateView.as_view(template_name=template)(request)

and I end up with a blank page on my browser. No error anywhere, just
a blank page.

Larry Martell

unread,
May 16, 2013, 4:22:55 PM5/16/13
to django...@googlegroups.com
On Sat, May 11, 2013 at 8:23 AM, Masklinn <mask...@masklinn.net> wrote:
> On 2013-05-11, at 15:57 , Larry Martell wrote:
>>
>> Yes, that is what I did. This is not in my urlconf. It's in a view
>> function. I replaced:
>>
>> return direct_to_template(request, template)
>>
>> by:
>>
>> return TemplateView.as_view(template_name=template)
>>
>> Is that not correct?
>
> Indeed not, `TemplateView.as_view(template)` is roughly equivalent to
> `functools.partial(direct_to_template, template=template)`: it's only
> one half of the operation, which returns a callable replying to
> requests.
>
> You need something along the lines of `TemplateView.as_view(template)(request)`

I am running into this same problem with RedirectView. In 1.4 I had a
view that was doing:

return redirect_to(request, new_report.url)

I changed it to:

return RedirectView.as_view(url=new_report.url)

and it's blowing up with:

Traceback:
File "/Library/Python/2.7/site-packages/django/core/handlers/base.py"
in get_response
187. response = middleware_method(request, response)
File "/Library/Python/2.7/site-packages/django/contrib/sessions/middleware.py"
in process_response
26. patch_vary_headers(response, ('Cookie',))
File "/Library/Python/2.7/site-packages/django/utils/cache.py" in
patch_vary_headers
142. if response.has_header('Vary'):

I tried doing something similar to what you suggested with
TemplateView, but that didn't work:

RedirectView.as_view(url=new_report.url)(request)
*** TypeError: a float is required

Masklinn

unread,
May 16, 2013, 4:37:55 PM5/16/13
to django...@googlegroups.com
Do you have a full traceback? Does `new_report.url` contain format metacharacters such as %f?

Larry Martell

unread,
May 16, 2013, 4:41:03 PM5/16/13
to django...@googlegroups.com
That is the full traceback I get the browser.

> Does `new_report.url` contain format metacharacters such as %f?

Yes:

(Pdb) print new_report.url
/report/CDSEM/MeasurementData/?date_time=3%2F4%2F10&submit_preview=Generate+Report&group=&target_name=&tool_ids=15&recipe=&ep=&roi_name=&lot=&field_6=Date+Time&field_7=Bottom&field_4=Ep&field_5=Lot&field_2=Target&field_3=Recipe&field_1=Tool

Masklinn

unread,
May 16, 2013, 4:59:49 PM5/16/13
to django...@googlegroups.com
Looks like you probably need to escape (double) the % signs:
https://docs.djangoproject.com/en/1.5/ref/class-based-views/base/#django.views.generic.base.RedirectView

> The given URL may contain dictionary-style string formatting, which
> will be interpolated against the parameters captured in the URL. Because
> keyword interpolation is always done (even if no arguments are passed
> in), any "%" characters in the URL must be written as "%%" so that
> Python will convert them to a single percent sign on output.

But really, while I might somewhat see the point of using
TemplateView[0] I don't see the point of using RedirectView in that
manner, why not just return an HttpResponseRedirect[3]?

Class-based views are really for using in URL mappings (potentially
custom subclasses), not for using in your own view functions.

[0] Still, it would probably be simpler to use TemplateResponse[1]
directly, or render_to render_to_response[2] if it's sufficient
[1] https://docs.djangoproject.com/en/dev/ref/template-response/#templateresponse-objects
[2] https://docs.djangoproject.com/en/dev/topics/http/shortcuts/#django.shortcuts.render_to_response
[3] https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpResponseRedirect

Larry Martell

unread,
May 16, 2013, 5:19:36 PM5/16/13
to django...@googlegroups.com
Tried this, got the same error.

> But really, while I might somewhat see the point of using
> TemplateView[0] I don't see the point of using RedirectView in that
> manner, why not just return an HttpResponseRedirect[3]?

I don't know I didn't write this and the original developer is gone.
I'm just trying to upgrade to 1.5, and based on what I read at
https://docs.djangoproject.com/en/1.4/topics/generic-views-migration/
I changed all the calls to redirect_to to RedirectView. I changed this
to HttpResponseRedirect as you suggested and it's working. Thanks once
again.

Larry Martell

unread,
May 16, 2013, 5:21:29 PM5/16/13
to django...@googlegroups.com
Answering my own question, in case someone else is having the same
issue. For the POST's I changed the calls to direct_to_template to
TemplateResponse and now they are working in 1.5.
Reply all
Reply to author
Forward
0 new messages