Django: how to set content-type header to text/xml within a class-based view?

12,145

Solution 1

I think the key point is render_to_response in django.views.generic.base , whose code is this:

def render_to_response(self, context, **response_kwargs):
    """
    Returns a response, using the `response_class` for this
    view, with a template rendered with the given context.

    If any keyword arguments are provided, they will be
    passed to the constructor of the response class.
    """
    response_kwargs.setdefault('content_type', self.content_type)   # key
    return self.response_class(
        request=self.request,
        template=self.get_template_names(),
        context=context,
        **response_kwargs
    )

As for your case, May be you need this code:

class MyView(ListView):
    def get(self, request, *args, **kwargs):
        context = self.get_context_data()

        if self.kwargs.has_key('xml'):
            return self.render_to_response(context, content_type="text/xml; charset=utf-8")
        return self.render_to_response(context)

Solution 2

You don't need to write additional code. Use TemplateResponseMixin and set content_type attribute to whatever you need:

class MyView(TemplateResponseMixin):
    content_type='application/xml'
    ...

Solution 3

I made a middleware class based off of django-cors-headers so I could allow iframe-ing of part of my django app. I keep a middleware.py in my main project directory and save a couple random middleware classes I have made there, like this one here and a ForceResponse Exception for example.

import re
from django import http
from django.conf import settings

class XFrameAllowMiddleware(object):

    def process_request(self, request):
        """
        If CORS preflight header, then create an
        empty body response (200 OK) and return it

        Django won't bother calling any other request
        view/exception middleware along with the requested view;
        it will call any response middlewares
        """
        if (self.is_enabled(request) and
                request.method == 'OPTIONS' and
                "HTTP_ACCESS_CONTROL_REQUEST_METHOD" in request.META):
            response = http.HttpResponse()
            return response
        return None

    def process_response(self, request, response):
        if self.is_enabled(request):
            response['X-Frame-Options'] = 'ALLOWALL'
        return response

    def is_enabled(self, request):
        return re.match(settings.XFRAME_URLS_REGEX, request.path)

Add it to your MIDDLEWARE_CLASSES and configure the regex in your settings:

MIDDLEWARE_CLASSES = (
    ...
    'your_django_app.middleware.XFrameAllowMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    ...
)

XFRAME_URLS_REGEX = r'^/iframe_this_url/.*$'

from the django-cors-headers read.me:

CORS_URLS_REGEX: specify a URL regex for which to enable the sending of CORS headers; Useful when you only want to enable CORS for specific URLs, e. g. for a REST API under /api/. Example:

CORS_URLS_REGEX = r'^/api/.*$'

Default:

CORS_URLS_REGEX = '^.*$'
Share:
12,145
maremare
Author by

maremare

Updated on June 04, 2022

Comments

  • maremare
    maremare about 2 years

    I'm trying to do it this way, but it doesn't work.

    class MyView(View):
    
        def options(self, request, *args, **kwargs):
            """
            Handles responding to requests for the OPTIONS HTTP verb.
            """
            response = http.HttpResponse()
            if self.kwargs.has_key('xml'):
                response['Content-Type'] = 'text/xml; charset=utf-8'
            return response
    
  • maremare
    maremare about 10 years
    Thanks a lot! It can also be used in a such way, as I have figured out: class MyView(TemplateView): def render_to_response(self, context, **response_kwargs): response = super(HelpGivenView,self).render_to_response( context, **response_kwargs) if self.kwargs.has_key('xml'): response['Content-Type'] = 'text/xml; charset=utf-8' return response
  • benzkji
    benzkji about 5 years
    best answer. no method overriding, just adding an attribute to your view. wont get it cheaper!