Javascript can't post data to database

I am trying to send keystroke data to django admin from the registration form using javascript. Everything looks fine but data is not sent to the database. What could be the problem? i don’t get any errors.

I guess there are not much information in your question. Would be better if you could share view, HTML and js

Here is my view.py file

# analytics/views.py

from django.http import JsonResponse

def save_keystroke_data(request):
    if request.method == 'POST':
        # Process the POST request and save the keystroke data
        # Retrieve data from the request object, save it to the database, etc.
        # Example:
        key = request.POST.get('key')
        timestamp = request.POST.get('timestamp')
        # Save the data to the database or perform any necessary processing
        
        # Return a JSON response indicating success
        return JsonResponse({'status': 'success'})
    else:
        # Return a JSON response indicating failure (only accept POST requests)
        return JsonResponse({'status': 'error', 'message': 'Method not allowed'}, status=405)

Here is my html and js at the bottom.

{% extends 'core/base.html' %}

{% block head_title %}Banking System{% endblock %}

{% block content %}
{% if registration_form.non_field_errors %}
    {% for error in registration_form.non_field_errors %}
    <div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mt-2" role="alert">
        <p class="font-bold">Error!</p>
        <p class="block sm:inline">{{ error }}</p>
    </div>
    {% endfor %}
{% endif %}
{% if address_form.non_field_errors %}
    {% for error in address_form.non_field_errors %}
    <div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mt-2" role="alert">
        <p class="font-bold">Error!</p>
        <p class="block sm:inline">{{ error }}</p>
    </div>
    {% endfor %}
{% endif %}

<h1 class="font-mono font-bold text-3xl text-center pb-5 pt-10">Register</h1>
<hr />
<div class="w-full mt-10">
    <form method="post" class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4" id="registrationForm">
       

        {% csrf_token %}
        {% for hidden_field in registration_form.hidden_fields %}
            {{ hidden_field.errors }}
            {{ hidden_field }}
        {% endfor %}
        <div class="flex flex-wrap -mx-3 mb-6">
            <div class="w-full md:w-1/2 px-3 mb-6 md:mb-0">
                <label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="{{ registration_form.first_name.id_for_label }}">
                    {{ registration_form.first_name.label }}
                </label>
                {{ registration_form.first_name }}
                {% if registration_form.first_name.errors %}
                    {% for error in registration_form.first_name.errors %}
                        <p class="text-red-600 text-sm italic pb-2">{{ error }}</p>
                    {% endfor %}
                {% endif %}
            </div>
            <div class="w-full md:w-1/2 px-3">
                <label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="{{ registration_form.last_name.id_for_label }}">
                    {{ registration_form.last_name.label }}
                </label>
                {{ registration_form.last_name }}
                {% if registration_form.last_name.errors %}
                    {% for error in registration_form.last_name.errors %}
                        <p class="text-red-600 text-sm italic pb-2">{{ error }}</p>
                    {% endfor %}
                {% endif %}
            </div>
        </div>
        <div class="flex flex-wrap -mx-3 mb-6">
            <div class="w-full md:w-1/2 px-3 mb-6 md:mb-0">
                <label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="{{ registration_form.email.id_for_label }}">
                    {{ registration_form.email.label }}
                </label>
                {{ registration_form.email }}
                {% if registration_form.email.errors %}
                    {% for error in registration_form.email.errors %}
                        <p class="text-red-600 text-sm italic pb-2">{{ error }}</p>
                    {% endfor %}
                {% endif %}
            </div>
            <div class="w-full md:w-1/2 px-3 mb-6 md:mb-0">
                <label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="{{ registration_form.account_type.id_for_label }}">
                    {{ registration_form.account_type.label }}
                </label>
                {{ registration_form.account_type }}
                {% if registration_form.account_type.errors %}
                    {% for error in registration_form.account_type.errors %}
                    <p class="text-red-600 text-sm italic pb-2">{{ error }}</p>
                    {% endfor %}
                {% endif %}
            </div>
        </div>
        <div class="flex flex-wrap -mx-3 mb-6">
            <div class="w-full md:w-1/2 px-3 mb-6 md:mb-0">
                <label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="{{ registration_form.gender.id_for_label }}">
                    {{ registration_form.gender.label }}
                </label>
                {{ registration_form.gender }}
                {% if registration_form.gender.errors %}
                    {% for error in registration_form.gender.errors %}
                        <p class="text-red-600 text-sm italic pb-2">{{ error }}</p>
                    {% endfor %}
                {% endif %}
            </div>
            <div class="w-full md:w-1/2 px-3 mb-6 md:mb-0">
                <label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="{{ registration_form.birth_date.id_for_label }}">
                    {{ registration_form.birth_date.label }}
                </label>
                {{ registration_form.birth_date }}
                {% if registration_form.birth_date.errors %}
                    {% for error in registration_form.birth_date.errors %}
                    <p class="text-red-600 text-sm italic pb-2">{{ error }}</p>
                    {% endfor %}
                {% endif %}
            </div>
        </div>
        <div class="flex flex-wrap -mx-3 mb-6">
            <div class="w-full md:w-1/2 px-3 mb-6 md:mb-0">
                <label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="{{ registration_form.password1.id_for_label }}">
                    {{ registration_form.password1.label }}
                </label>
                {{ registration_form.password1 }}
                {% if registration_form.password1.errors %}
                    {% for error in registration_form.password1.errors %}
                        <p class="text-red-600 text-sm italic pb-2">{{ error }}</p>
                    {% endfor %}
                {% endif %}
            </div>
            <div class="w-full md:w-1/2 px-3 mb-6 md:mb-0">
                <label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="{{ registration_form.password2.id_for_label }}">
                    {{ registration_form.password2.label }}
                </label>
                {{ registration_form.password2 }}
                    {% if registration_form.password2.errors %}
                    {% for error in registration_form.password2.errors %}
                        <p class="text-red-600 text-sm italic pb-2">{{ error }}</p>
                    {% endfor %}
                {% endif %}
            </div>
        </div>

        {% for hidden_field in address_form.hidden_fields %} {{ hidden_field.errors }} {{ hidden_field }} {% endfor %}
        <div class="flex flex-wrap -mx-3 mb-6">
            <div class="w-full md:w-1/2 px-3 mb-6 md:mb-0">
                <label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="{{ address_form.street_address.id_for_label }}">
                    {{ address_form.street_address.label }}
                </label>
                {{ address_form.street_address }}
                {% if address_form.street_address.errors %}
                    {% for error in address_form.street_address.errors %}
                        <p class="text-red-600 text-sm italic pb-2">{{ error }}</p>
                    {% endfor %}
                {% endif %}
            </div>
            <div class="w-full md:w-1/2 px-3">
                <label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="{{ address_form.city.id_for_label }}">
                    {{ address_form.city.label }}
                </label>
                {{ address_form.city }}
                {% if address_form.city.errors %}
                    {% for error in address_form.city.errors %}
                        <p class="text-red-600 text-sm italic pb-2">{{ error }}</p>
                    {% endfor %}
                {% endif %}
            </div>
        </div>
        <div class="flex flex-wrap -mx-3 mb-6">
            <div class="w-full md:w-1/2 px-3 mb-6 md:mb-0">
                <label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="{{ address_form.postal_code.id_for_label }}">
                    {{ address_form.postal_code.label }}
                </label>
                {{ address_form.postal_code }}
                {% if address_form.postal_code.errors %}
                    {% for error in address_form.postal_code.errors %}
                        <p class="text-red-600 text-sm italic pb-2">{{ error }}</p>
                    {% endfor %}
                {% endif %}
            </div>
            <div class="w-full md:w-1/2 px-3">
                <label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="{{ address_form.country.id_for_label }}">
                    {{ address_form.country.label }}
                </label>
                {{ address_form.country }}
                {% if address_form.country.errors %}
                    {% for error in address_form.country.errors %}
                        <p class="text-red-600 text-sm italic pb-2">{{ error }}</p>
                    {% endfor %}
                {% endif %}
            </div>

            <div class="w-full md:w-1/2 px-3">
                <label class="block lowercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="inputPhrase">
                    Please type "cyber resilience 2024" 20 times:
                </label>
                <textarea id="inputPhrase" name="inputPhrase" rows="10" cols="50" class="border rounded-md px-3 py-2" onkeyup="sendDataToServer(this.value.slice(-1), new Date().toISOString())"></textarea>
                <div id="phraseError" class="hidden text-red-600 text-sm italic pb-2">Please type "cyber resilience 2024" 20 times.</div>

            </div>
            

        </div>
        <div>
            <input type="hidden" id="keystrokesData" name="keystrokesData">
        </div>
        


        <div class="flex items-center justify-between">
            <button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline" type="submit">
                Register
            </button>
        </div>
    </form>
</div>
<script>
document.getElementById('registrationForm').addEventListener('submit', function(event) {
    var inputPhrase = document.getElementById('inputPhrase').value;
    var phraseCount = (inputPhrase.match(/cyber resilience 2024/g) || []).length;

    // Prevent form submission if phrase count is insufficient
    if (phraseCount < 20 || isPasted) {
        event.preventDefault();
        document.getElementById('phraseError').classList.remove('hidden');
    }
});

// Add event listener for paste event
document.getElementById('inputPhrase').addEventListener('paste', function(event) {
    var pastedText = (event.clipboardData || window.clipboardData).getData('text');
    if (pastedText.includes('cyber resilience 2024')) {
        event.preventDefault();
        alert("Pasting is not allowed! Please type");
    }
});
</script>
<script>
function sendDataToServer(key, timestamp) {
    var data = new FormData();
    data.append('key', key);
    data.append('timestamp', timestamp);

    var xhr = new XMLHttpRequest();
    xhr.open('POST', '/save-keystroke-data/', true);
    xhr.onreadystatechange = function() {
        if (xhr.readyState === XMLHttpRequest.DONE) {
            if (xhr.status === 200) {
                console.log('Keystroke data sent successfully.');
            } else {
                console.error('Failed to send keystroke data. Status: ' + xhr.status);
            }
        }
    };
    xhr.send(data);
}

</script>


{% endblock %}

Side note: When posting code, templates, or error messages here, enclose the code between lines of three backtick - ` characters. This means you’ll have a line of ```, then your code, then another line of ```. This forces the forum software to keep your code properly formatted. (I’ve taken the liberty of fixing your original post for you.)

I don’t see any code in your view where you’re even trying to save data to the database.

Also, I don’t envision any situation where this is going to work “at scale”. I don’t see the server being able to keep up with the flood of post requests from more than 2 or 3 users. You need to be aware that every POST request is going to require a minimum of 4 tcp packets being exchanged - worse if you’re using SSL, and probably in the neighborhood of at least 500 bytes in each request.

If you’re going to try to do something like this, you should at least be using a websocket to avoid all the connection overhead for each request.

1 Like

how do i improve the code in my view?

How do i use websocket?

What would be the recommended way at a large scale?

can you help i am a beginner

Have you worked your way through the Official Django Tutorial? If you haven’t, you should. It’ll present you with a lot of the fundamentals you need to understand how Django works. If you have, then you should review the work you had done in the sections where it shows how you update the database.

Start here: Django Channels — Channels 4.1.0 documentation

Depends upon what you mean by “large”. At more than (about) 100 users, you’re going to have some real architectural issues to address in a couple different areas.

At a minimum, you don’t want to try to send these as individual keystrokes. You’d want to collect the keystrokes into batches, and send them periodically, like once every 15 seconds.

When I run across questions like this, my first reaction is to ask “Why?”. What information do you hope to obtain from this? Is there another way to gather that information?

Let me review once again the official Django Tutorial

I intend my system to be used by more than 100 users

I want my system to collect keystrokes and later use them as an additional layer for authentication, when a user types the username and password, later keystrokes will be used to authenticate if he/she is the one who claims he/she is.

Oh, that’s right. I remember that conversation now. (Django Login using behavior biometrics - #4 by KenWhitesell)

Yes, this is what i want to achieve but i have been struggling to capture these keystrokes.

How can i achieve that? Here is my views.py trying to save data into the database.

# analytics/views.py
from django.http import JsonResponse
from .models import KeystrokeData

def save_keystroke_data(request):
    if request.method == 'POST':
        # Extract data from the POST request
        key = request.POST.get('key')
        timestamp = request.POST.get('timestamp')

        # Save the keystroke data to the database
        keystroke_data = KeystrokeData.objects.create(key=key, timestamp=timestamp)
        
        # Optionally, you can perform additional processing or validation here
        
        # Return a JSON response indicating success
        return JsonResponse({'status': 'success'})
    else:
        # Return a JSON response indicating failure (only accept POST requests)
        return JsonResponse({'status': 'error', 'message': 'Method not allowed'}, status=405)

I am still stack on this problem, is there anyway someone can help me?

From my point of view this could be a real mess. How i would approach this is by timing every keystroke that makes up a bunch of words. this data could be fit into a dataframe, preprocessed and then used to train an ML model. the model should learn how different users deal with letters of the words. Could be a case of one vs rest classification.
But the problem here is every time a new user joins you will need to retrain the model with proper input data from the new user or it will result in a model trained on an unbalanced data.

And have you tried Ajax? it helps collect realtime data without reloading the page. Do give it a shot it should probably work.

This is a cool idea let me know it you find some insights on it.

As I pointed out in my other response, there are so many things fundamentally wrong with this idea that I think you are wasting your time trying to implement this within the browser. The most significant issue that you’re going to deal with is the irregularity of the clock intervals being recorded by keystroke. The triggering of the keyup event is neither synchronous nor instantaneous, which means that everything else in the system is going to affect the time between when the key is released and the time the event is triggered - as well as the time it takes to get the current time. Therefore, even if you were mechanically pressing keys at a half-second interval, there’s going to be a wide variance of intervals recorded.

Thank you for your inputs let me try on Ajax and see how far i can go

Thank you so much for this clarification. So from your point of view what could be the best approach for me to implement this idea apart from the browser?

I don’t know. That’s completely outside the realm of anything related to Django.

Thank you for your corporation, i appreciate.