Previous Page Next Page

Implementing a Request Preprocessor

You implement a request preprocessor by defining a process_request(self, request) function in the middleware class. The process_request() function is called after the request has been received but before the URL gets resolved to determine which view function to run.

The process_request() function is passed the HttpRequest object of the request. Any changes you make to the HttpRequest object are also passed down to the view function.

The process_request() function can return either None or an HttpResponse object. If None is returned, Django continues processing the request. However, if you return an HttpResponse object, the request immediately returns that response.

Watch Out!

No other middleware applications or view functions run if an HttpResponse is returned.


The SetRemoteAddrFromForwardedFor application uses the following code snippet to replace the REMOTE_ADDR attribute of the request with the HTTP_X_FORWARDED_FOR attribute for requests coming through a proxy:

def process_request(self, request):
    try:
        real_ip = request.META['HTTP_X_FORWARDED_FOR']
    except KeyError:
        pass
    else:
        real_ip = real_ip.split(",")[0]
        request.META[REMOTE_ADDR'] = real_ip

Try It Yourself: Create and Install a Request Preprocessor Middleware Application

In this section, you will create and install a view preprocessor application, called CustomViewLogger, that logs information about view functions before they are run. You will also create a new application called Log in the database, and then you will define a new RequestEvent model in the Log application to store information about requests. You will also implement a new view_log() view function and template that will render the RequestEvent objects.

By the Way

The examples in this hour are just meant to illustrate data that can be accessed in the middleware. If you want to implement a logging system for a large website that has numerous requests, you will probably want to use another method, such as a buffered file, for storage than the site database.


Follow these steps to implement a request preprocessor middleware application:

1.
Stop the development server.

2.
Use the following command at the root of the iFriends project to create a new application called Log:

python manage.py startapp Log

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

4.
Add the following import statement to the file, shown in Listing 19.1, to import the User object so that you can use it in your models:

from django.contrib.auth.models import User

5.
Add the RequestEvent model to the file, shown in Listing 19.1, to define a RequestEvent object that can store information about the request.

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

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

8.
Create a file named django/middleware/custom.py in your Django installation.

By the Way

The built-in middleware is installed in the django/middleware directory. However, you can put your middleware applications anywhere Python can find them.

9.
Add the following imports to the file, shown in Listing 19.2, to import the RequestEvent object you defined in step 5 and the datetime class that you will use to record the time of the request:

from iFriends.Log.models import RequestEvent
from datetime import datetime

10.
Add the CustomRequestLogger middleware class definition to the file and define the process_request() function, shown in Listing 19.2, that collects information about the request and stores it in a RequestEvent in the database.

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

12.
Create and open a file called iFriends/templates/Custom/view_request_log.html in an editor.

13.
Add the contents shown in Listing 19.3 to the file.

14.
Save the iFriends/templates/Custom/view_request_log.html file.

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

16.
Add the view_log() view function, shown in Listing 19.4, to the file. The evType='request' argument is needed for later examples, as is using the lTemplate variable to define the template file to render.

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

18.
Open the iFriends/urls.py file in an editor.

19.
Add the following URL pattern to enable the view_log() function and collect the evType argument from the URL:

(r'^admin/view_log/(?P<evType>\w+)/$', 'iFriends.Custom.views.view_log'),

20.
Save the iFriends/urls.py file.

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

22.
Add the following line to the MIDDLEWARE_CLASSES setting to install the CustomRequestLogger application:

'django.middleware.custom.CustomRequestLogger',

23.
Save the iFriends/settings.py file.

24.
Start the development server.

25.
Access several nonadmin web pages in the iFriends site. Access the following URL to view the request log generated by the CustomRequestLogger application, shown in Figure 19.1:

http://127.0.0.1:8000/admin/view_log/request/

Figure 19.1. The view_log() function displaying the RequestEvent log.


Listing 19.1. The Imports and RequestEvent Definition of the iFriends/Log/models.py File

from django.db import models
from django.contrib.auth.models import User

class RequestEvent(models.Model):
    event = models.CharField('Event', max_length=30)
    date = models.DateTimeField('Date')
    user = models.ForeignKey(User)
    addr = models.CharField('IP Address', max_length=20)
    url = models.CharField('Url', max_length=80)

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

    class Admin:
        pass

Listing 19.2. The Imports and CustomRequestLogger Definition of the django/middleware/custom.py File

from iFriends.Log.models import RequestEvent
from datetime import datetime

class CustomRequestLogger(object):
    def process_request(self, request):
        try:
            if not request.META['PATH_INFO'].startswith('/admin'):
                event = RequestEvent()
                event.event = "Request"
                event.user = request.user
                event.addr = request.META['REMOTE_ADDR']
                event.date = datetime.now()
                event.url = request.META['PATH_INFO']
                event.save()
        except KeyError:
            pass
        return None

Listing 19.3. Full Contents of the iFriends/templates/Custom/view_request_log.py File

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

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

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

@staff_member_required
def view_log(request, evType='request'):
    lTemplate = 'Custom/view_request_log.html'
    logList = RequestEvent.objects.all()

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


Previous Page Next Page