Previous Page Next Page

Implementing a Response Postprocessor

You implement a response postprocessor by defining a process_response(self, request, response) function in the middleware class. The process_response() function is called after the HttpResponse has been created but before it is returned to the browser.

The process_response() function is passed the HttpRequest and HttpResponse objects as arguments. Any changes you make to the HttpResponse object also are passed back to the browser. The process_response() function is an excellent way to make modifications globally to verify responses and make changes to them before they are passed back to the browser.

The process_response() function must return only an HttpResponse object. You can pass back the HttpResponse that was passed in, or you can pass back an entirely different one. For example, the following code snippet globally modifies all responses to include footers at the bottom of the HTML document:

class AddFooter(object):
    def process_response(self, request, response):
        footer = "<HR>This page was generated by iFriends /
                  \n</body>\n</html>"
        contents = response.content
        contents = contents.replace('</body>\n</html>', footer)

        return None

Try It Yourself: Create and Install a Response Postprocessor Middleware Application

In this section, you will create and install a response postprocessor application called CustomResponseLogger that logs information about responses before they are sent to the browser. You will also define a new ResponseEvent model in the Log application to store information about the response before it is sent back to the browser. You will also create a template that the view_log() view function will use to render the ResponseEvent objects.

Follow these steps to implement a response postprocessor middleware application:

1.
Stop the development server.

2.
Open the iFriends/Log/models.py file in an editor.

3.
Add the ResponseEvent model to the file, as shown in Listing 19.9, to define a ResponseEvent object that can store information about the response.

4.
Save the iFriends/Log/models.py file.

5.
Synchronize the database using the manage.py syncdb command from the root of the iFriends project.

6.
Open the django/middleware/custom.py file in your Django installation.

7.
Add the following import to the file, as shown in Listing 19.10, to import the ResponseEvent object you defined in step 3:

from iFriends.Log.models import ResponseEvent

8.
Add the CustomResponseLogger middleware class definition to the file and define the process_response() function, as shown in Listing 19.10. This will collect information about the view request and store it in a ResponseEvent object in the database.

9.
Save the django/middleware/custom.py file.

10.
Create and open a file called iFriends/templates/Custom/view_response_log.html in an editor.

11.
Add the contents shown in Listing 19.11 to the file.

12.
Save the iFriends/templates/Custom/view_response_log.html file.

13.
Open the iFriends/Custom/views.py file in an editor.

14.
Add the following code to the view_log() view function, as shown in Listing 19.12. It sets lTemplate to the view_response_log.html file and logList to the ResponseEvent objects if evType is set to response:

elif evType == "response":
    lTemplate = 'Custom/view_response_log.html'
    logList = ViewResponse.objects.all()

15.
Save the iFriends/Custom/views.py file.

16.
Open the iFriends/settings.py file in an editor.

17.
Add the following line to the MIDDLEWARE_CLASSES setting to install the CustomResponseLogger application:

'django.middleware.custom.CustomResponseLogger',

18.
Save the iFriends/settings.py file.

19.
Start the development server.

20.
Access several nonadmin web pages in the iFriends site. Access the following URL to view the log report, as shown in Figure 19.3, generated by the CustomResponseLogger application:

http://127.0.0.1:8000/admin/view_log/response/

Figure 19.3. The view_log() function displaying the ResponseEvent log.


Listing 19.9. The ResponseEvent Definition of the iFriends/Log/models.py File

class ResponseEvent(models.Model):
    event = models.CharField('Event', max_length=30)
    date = models.DateTimeField('Date')
    user = models.ForeignKey(User, blank=True, null=True)
    addr = models.CharField('IP Address', max_length=20)
    url = models.CharField('Url', max_length=80)
    size = models.IntegerField('Size')

    def __str__(self):
        return '%s - %s' % (self.event, self.date)

    class Admin:
        pass

Listing 19.10. The Imports and CustomResponseLogger Definition of the django/middleware/custom.py File

from iFriends.Log.models import ResponseEvent
. . .
class CustomResponseLogger(object):
    def process_response(self, request, response):
        try:
            if not request.META['PATH_INFO'].startswith('/admin'):
                event = ResponseEvent()
                event.event = "Response"
                event.user = request.user
                event.addr = request.META['REMOTE_ADDR']
                event.date = datetime.now()
                event.url = request.META['PATH_INFO']
                event.size = len(response.content)
                event.save()
        except KeyError:
            pass
        return response

Listing 19.11. Full Contents of the iFriends/templates/Custom/view_response_log.py File

{% extends "admin/base_site.html" %}
{% block title %}Response Log Report{% endblock %}

{% block content %}
<h1>Response Log Report</h1>
<table>
<tr>
<th>Date</th><th>User</th><th>IP Address</th><th>URL</th><th>Size</th>
</tr>
{% for entry in logList %}
    <tr>
        <td>{{ entry.date }}</td>
        <td>{{ entry.user }}</td>
        <td>{{ entry.addr }}</td>
        <td>{{ entry.url }}</td>
        <td>{{ entry.size }}</td>
    </tr>
{% endfor %}
</table>
{% endblock %}

Listing 19.12. The view_log() View Function of the iFriends/Custom/views.py File

@staff_member_required
def view_log(request, evType='request'):
    if evType == "view":
        lTemplate = 'Custom/view_view_log.html'
        logList = ViewEvent.objects.all()
    elif evType == "response":
        lTemplate = 'Custom/view_response_log.html'
        logList = ResponseEvent.objects.all()
    else:
        lTemplate = 'Custom/view_request_log.html'
        logList = RequestEvent.objects.all()

    return render_to_response(lTemplate, {'logList': logList})


Previous Page Next Page