SLATER
SLATER

Reputation: 683

Django: what is the best way to prevent multiple click on a button?

I have a Django form with a popup confrimation before form validation. When validated, I save form data in a table, update 2 other tables, send an email and user is redirected to another confirmation page.

It works but it may be slow in some situation. And in these situation, I have experienced the case a user click another time. Doing that, form data are sent again but form validation failed (normal behavior to prevent duplicate) but user is never redirected to the confirmation page and that is problematic.

To fix this issue, I would like :

  1. to prevent user to be able to click 2 times the popup button (disable after first click)
  2. improve data process in my view
  3. improve my logic

For the first point, I must use JS, right? For the second point, as 2 table are update, I think using update would be better For the third, ?

thanks for advice

def randomisation_edit(request):

    if request.method == "POST":
        form = RandomisationForm(request, data=request.POST or None)
        if form.is_valid():
            randomisation = form.save()
            pays = randomisation.ran_num[0:3].upper()
            centre = randomisation.ran_num[4:6].upper()
            status = randomisation.ran_vih
            severity = randomisation.ran_sta
            rand = Randomiser(pays, centre, status, severity)
 
            # Mise à jour de la base de données -> Patient code pour rendre indisponible la ligne
            # pour une prochaine randomisation

            # ListeRandomisation
            # 1.Récupération de la ligne dans la liste de rando
            bras = rand['bras']

            # 2.Mise à jour de la ligne dans la liste de rando
            patient = get_object_or_404(ListeRandomisation, ran_ide = bras)
            patient.pat = randomisation.ran_num # pat
            patient.save()

            # Medicament
            # 1.Récupération de la ligne dans la liste de correspondance médicament
            medicament = rand['medicament']

            # 2.Mise à jour de la ligne dans la liste de correspondance médicament
            medicament = get_object_or_404(Medicament, med_ide = medicament)
            medicament.pat = randomisation.ran_num # pat
            medicament.save()

            pays = randomisation.ran_num[0:3].upper()
            centre = randomisation.ran_num[4:6].upper()
            request.session['can_randomize'] = is_randomizable(pays, centre)

            # 3. Mise à jour de la table Randomisation avec le bras et le numéro de boite attribués
            randomisation.ran_bra = patient.ran_bra
            randomisation.ran_med = medicament.med_num
            randomisation.ran_log_dat = timezone.now() # datetime.now(timezone.utc)
            randomisation.ran_log = request.user.username
            # randomisation.ran_log_sit = request.session.get('selected_site') 
            randomisation.ran_log_sit = request.session.get('user_site')
            randomisation.save()

            email('randomisation',randomisation.ran_num,randomisation.ran_bra,medicament.med_num,'',randomisation.ran_log,patient.ran_ide,medicament.med_ide,randomisation.ran_vih,randomisation.ran_sta)

            return redirect('randomization:confirmation', pk = randomisation.pk)

    else:
        form = RandomisationForm(request)

    return render(request, 'randomization/randomisation_edit.html', {'form': form})

Upvotes: 1

Views: 2606

Answers (2)

Ramy M. Mousa
Ramy M. Mousa

Reputation: 5943

I prefer doing things the backend way because unlike frontend, it cannot be easily bypassed. So I found Django Rate limit to be fairly simple.

It stores a user-specific value such as IP address to cache instantly as the first request arrives. since the cache is really fast, then before second click happens there would be a value stopping the same user from executing the same functionality.

  • pip install django-ratelimit

from ratelimit.decorators import ratelimit

@ratelimit(key='ip')
def myview(request):
    # ...

@ratelimit(key='ip', rate='100/h')
def secondview(request):
    # ...

Upvotes: 1

David Silveiro
David Silveiro

Reputation: 1602

Doing this with Django seems like a little much, I feel this issue is better handled on the front-end. We could use Jquery to disable our button, which should eliminate any errors you're facing.

We'll start off by referencing our form #myForm, when submitted, will set our attribute to disabled

$('#myForm').one('submit', function() {
    $(this).find('input[type="submit"]').attr('disabled','disabled');
}); 

Upvotes: 2

Related Questions