djangodjango-middlewaredjango-logging

Django Logging all the GET requests


I'm trying to put all the GET requests that appear in console into the database from django. For example:

console log:

[23/May/2019 13:58:44] "GET /testapp/ HTTP/1.1" 200 409
[23/May/2019 13:58:45] "GET /testapp/page2/ HTTP/1.1" 200 172

I'm trying to get the timestamp, page URL and user name from it and put in the database, so the entries looks something like this in the database:

id  user    pageURL        timeStamp
96  naeem   /testapp/       2019-05-23 09:37:12.640613
97  naeem   /testapp/page2/ 2019-05-23 09:37:13.317271

This is the code I have written for the middleware:

from TestApp.models import ActivityLog


class AccessLogs(object):

    # One-time config
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)

        # Add the user and page info into DB
        try:
            ActivityLog(user=request.user, pageURL=request.path).save()
        except Exception as e:
            print(e)

        return response

The problem is that it gives me the desired result, but it does not get the results if I click on a downloadable file, or an image. Like I have a static image on the website which is downloaded on click, like:

<a href="{% static 'TestApp/media/cat.jpg' %}" download>Click here to open image</a>

So if I click on that, it shows in the console that the image was downloaded, but it doesn't put that in the database. Is there any way to make this work? Any help will be appreciated!

EDIT: settings.py:

import os

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

SECRET_KEY = ''

DEBUG = True

ALLOWED_HOSTS = []

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'TestApp',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'TestApp.middleware.LoggingMiddleware.AccessLogs',
]

ROOT_URLCONF = 'Test.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'Test.wsgi.application'

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True

STATIC_URL = '/static/'
MEDIA_URL = '/media/'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'media')
]

Models:

from django.db import models

class ActivityLog(models.Model):
    user = models.CharField(max_length=1024)
    pageURL = models.CharField(max_length=1024)
    timeStamp = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "activity_logs"

EDIT2: The file I'm trying to access is stored in TestWebsite/TestApp/static/TestApp/media/cat.jpg

TestWebsite/TestApp/url.py:

from django.urls import path

from . import views

urlpatterns = [
    path('', views.homePage, name='homePage'),
    path('page2/', views.homePage2, name='homepage2')
]

TestWebsite/TestWebsite/urls.py

from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from django.views.static import serve
from django.views.decorators.cache import never_cache

nocache_serve = never_cache(serve)

urlpatterns = [
    path('admin/', admin.site.urls),
    path('testapp/', include('TestApp.url')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT, view=nocache_serve)

TestWebsite/TestApp/views.py:

from django.shortcuts import render, HttpResponse
import datetime

def homePage(request):
    time = datetime.datetime.now()
    return render(request, "TestApp/homePage.html", {"time": time})

def homePage2(request):
    return render(request, "TestApp/homePage2.html")

Solution

  • In general Django's Middleware are created for effective request/response management. It has own phases (process_request(), process_view(), process_response()) and so on. Every time request reaches on server, Middleware is called (But This does not happen every time, when serving static files). This is because of caching behaviour. Django caches static/media files in browser cache (using Cache-Control header). When resource is cached, on next request resource is read from browser cache and request does not reach on the server. Django uses from django.views.static import serve method for serving static/media files. (This method sets correct HTTP headers for caching).

    In your urls.py add these lines. This is the most important here.

    from django.conf import settings
    from django.conf.urls.static import static
    from django.views.static import serve
    from django.views.decorators.cache import never_cache
    
    nocache_serve = never_cache(serve) # never_cache is view decorator. we can use here, also. This will set correct HTTP headers to avoid caching behaviour.
    urlpatterns = [
        #
        # your path goes here
        #
    ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT, view=nocache_serve)
    

    settings.py

    # I think you already have this configuration in settings.
    STATIC_URL = '/static/'
    MEDIA_URL = '/media/'
    STATICFILES_DIRS = [
        os.path.join(BASE_DIR, 'media')
    ]
    

    Now, You can log all incoming request (But do not forget, to avoid caching behaviour of static/media files is bad idea).

    Do not forget to clear browser cache and restart server after adding this code.

    Hope it helps.