Django (or something) makes Multitudes of Get requests (or my code is wrong) for both AJAX and standard scenario

By standard scenario I mean you have a base page A, with a button for adding an item to a list, the button is the submit button of a form so that you make a “POST” request to the page with some data. So then I reserve GET requests for just showing the page. That would result in 4-6 items being added to my UL instead of just 1.

Now I’m doing it with AJAX which is the proper way I guess and it’s doing much worse!

Here is relevant code:

ArrowGlue/db/views.py:

    statement = Statement.nodes.get(uid=statement_id)
    
    if statement is None:
        return HttpResponseRedirect('test1') # TODO error page
    
    add_given_form = add_goal_form = None
    
    if request.method == 'POST':
        part = request.POST.get('statement_part')
        
        if part == 'given':
            index = len(statement.given_indices)
            statement.given_indices.append(index)
            form = add_given_form = AddToStatementForm(request.POST)
        elif part == 'goal':
            index = len(statement.goal_indices)
            statement.goal_indices.append(index)
            form = add_goal_form = AddToStatementForm(request.POST)            
        else:
            assert 0
        
        content = Content(display_index=index, maintainer='Debug')
        content.save()

        if form.is_valid():
            kind = form.cleaned_data['kind']
        
            if kind == 'sketch':                
                sketch = DiagramSketch()
                sketch.save()
                content.sketch.connect(sketch)                       
                content.save()
            elif kind == 'text':
                pass
            else:
                assert 0
                
            statement.content.connect(content)            
            statement.save()
        else:
            return redirect(reverse('test1')) #TODO
    
    if add_given_form is None:
        add_given_form = AddToStatementForm()
        
    if add_goal_form is None:
        add_goal_form = AddToStatementForm()        
        
    if len(statement.given_indices) + len(statement.goal_indices):
        query = f'''
        MATCH (s:Statement)-[r:CONTAINS]->(c:Content)
        RETURN c
        '''       
        results = db.cypher_query(query)
        if results:
            results = results[0]
            results = [Content.inflate(res[0]) for res in results if res]
            givens = set(statement.given_indices)
            goals = set(statement.goal_indices)
            givens = list(filter(lambda c: c.display_index in givens, results))
            goals = list(filter(lambda c: c.display_index in goals, results))
        else:
            givens = []
            goals = []
    else:
        givens = []
        goals = []        
    
    context = {
        'statement': statement,
        'givens': givens,
        'goals': goals,
        'add_goal_form': add_goal_form,
        'add_given_form': add_given_form,
    }
    
    return render(request, 'db/edit_statement.html', context)

ArrowGlue/db/urls.py:

import db.views as views
from django.urls import path

urlpatterns = [
    path("react-example1/", views.react_index1, name="react_example1"),
    path("test1/", views.test1, name='test1'), 
    path("edit-statement/<str:statement_id>", views.edit_statement, name='edit_statement'),
    path("new-statement/", views.new_statement, name='new_statement'), 
    path("edit-proof/<str:proof_id>", views.edit_proof, name='edit_proof'), 
    path("new-proof/", views.new_proof, name='new_proof')
]

from django import forms
from ArrowGlue.settings import MAX_DB_TEXT_LENGTH

class NewProofForm(forms.Form):
    title = forms.CharField(label="Proof Title", max_length=MAX_DB_TEXT_LENGTH)
    
class NewStatementForm(forms.Form):
    title = forms.CharField(label="Statement Title", max_length=MAX_DB_TEXT_LENGTH)
    
class AddToStatementForm(forms.Form):
    kind = forms.ChoiceField(choices=(('text', 'Purely textual language'),('sketch', 'Diagram sketch')))
    

ArrowGlue/templates/db/edit_statement.html:


{% load crispy_forms_tags %}

{% block content %}
<h1>{{ statement.text }}</h1>

<p>
    <h2>Givens</h2>
    <ul id="given-list">
        {% for given in givens %}
            <li>{{ given.text }}</li>
        {% endfor %}    
        <li>
            <form method="POST" id="add-given-form" action="#">
                {% csrf_token %}
                {{ add_given_form|crispy }}
                <input type="hidden" name="statement_part" value="given">
                <button type="submit" class="btn btn-primary">+</button>
            </form>
        </li>
    </ul>
    
</p>

<p>
    <h2>Goals</h2>
    <ul id="goal-list">
        {% for goal in goals %}
            <li>{{ goal.text }}</li>
        {% endfor %}    
        <li> 
            <form method="GET" id="add-goal-form">
                {% csrf_token %}
                {{ add_goal_form |crispy }}
                <input type="hidden" name="statement_part" value="goal">
                <button type="submit" class="btn btn-primary">+</button>
            </form>
        </li>
    </ul>    
</p>

<script>
    function ajax_post_form(form, on_success)
    {
        form.submit(function() {
            $.ajax({ // create an AJAX call...
                data: $(this).serialize(), // get the form data
                type: $(this).attr('method'),
                url: $(this).attr('action'),
                success: on_success,
            });
        }
    }


    $(document).ready(function() { // this waits until the document is fully loaded
        // Put custom logic here   
        
        $("#add-given-form").submit(function() { // catch the form's submit event
            ajax_post_form($(this), function(response) {
                $("#given-list").append(response['text']);                    
            });
        
            return false;
        });
        
        $("#add-goal-form").submit(function() { // catch the form's submit event
            ajax_post_form($(this), function(response) {
                $("#given-list").append(response['text']);                    
            });
        
            return false;
        });
    }
</script>

{% endblock %}

Not sure how to fix this one!

Debug output:

[07/Aug/2024 15:37:00] “GET /db/new-statement/ HTTP/1.1” 200 1056
[07/Aug/2024 15:37:00] “GET /db/new-statement/ HTTP/1.1” 200 1056
[07/Aug/2024 15:37:07] “POST /db/new-statement/ HTTP/1.1” 302 0
[07/Aug/2024 15:37:08] “GET /db/edit-statement/4a266da937a348ff9772b9afb8316c45 HTTP/1.1” 200 3288
[07/Aug/2024 15:43:30] “POST /db/edit-statement/4a266da937a348ff9772b9afb8316c45 HTTP/1.1” 200 3762
[07/Aug/2024 15:46:35] “GET /db/edit-statement/4a266da937a348ff9772b9afb8316c45?csrfmiddlewaretoken=hymoTjeYxoW31rrYEOvyxGdyYm719aRPGL79tt2h45UtDmdXTzS3QwdFIhqyc0iW&kind=text&statement_part=goal HTTP/1.1” 200 3753
[07/Aug/2024 15:46:40] “POST /db/edit-statement/4a266da937a348ff9772b9afb8316c45?csrfmiddlewaretoken=hymoTjeYxoW31rrYEOvyxGdyYm719aRPGL79tt2h45UtDmdXTzS3QwdFIhqyc0iW&kind=text&statement_part=goal HTTP/1.1” 200 4196

Granted this looks normal, but when I’m debugging it’s seeming like it’s not my code but Django calling the view 4-20 times!

IDK what’s going on… -_-

Picture of unuseable UX:

I’m solving it guys, I think my Form handling is wrong and should be done in a separate function. Will get back to this post.

Nevermind. It’s ridiculous. I’m returning a JsonResponse now from a separate add_statement_given function. It’s doing the same thing!

you means that problem solved?

@white-seolpyo opposite of that. The problem persists no matter how correct I make the approach.

Where is your updated - new code?

It might be helpful to see the actual html as it exists in the browser, too.

As an example of one issue that could be happening, this jQuery expression:

could be executed multiple times if there are multiple elements matching the selector, or if it’s registered mutiple times.

One of the ways to identify siutations like this would be to add JavaScript console.log statements at key points to trace what’s happening, or to set a JavaScript breakpoint and walk through the code with a debugger.

1 Like

Got it to work now, just doing some reading up on forms and recoding it. Not sure what was the critical fix. But here’s a screenshot:

Now it’s just adding givens to the goals, but that’s another problem.

To post to the same page I’m using a <form> tag without action.