winixxee
winixxee

Reputation: 564

prevent multiple submissions when user clicks submit button multiple times before loading to the new page

I have googled around and it seems like there are many possibilities for php. But I haven't found anything good solution for django. I saw some people using client side javascript code for this, but I just don't get how to fix this. Problem I;m having is:when user writes a post, and click submit button fast twice before new page gets loaded then two posts will be made. Here's my code, thanks in advance. my html

<form id="post_form" method="post" action="/add_post/" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form|crispy }}
<input type="submit" name="submit" value="submit">
</form>

my views.py

class PostCreateView(CreateView):

    model = Post
    form_class = PostForm
    template_name = 'main/add_post.html'

    def form_valid(self, form):

        self.object = form.save(commit=False)
        # any manual settings go here

        #self.object.category = Category.objects.filter(category__in=categories).all()

        self.object.moderator = self.request.user
        self.object.image = extract(self.object.url) 
        self.object.thumbnail = extractt(self.object.content)
        self.object.save()
        return HttpResponseRedirect(reverse('post', args=[self.object.slug]))

    @method_decorator(login_required)
    def dispatch(self, request, *args, **kwargs):
        return super(PostCreateView, self).dispatch(request, *args, **kwargs)       

Edit: I changed it to like this

{% block content %}
<div class="col-sm-5">
<form id="post_form" method="post" action="/add_post/" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form|crispy }}
<input type="submit" id="button" name="submit" value="올리기">
</form>
</div>
<div class="col-sm-4" style="width:400px; height:250px; border:1px solid black;">
<h3>rule</h3>

</div>

<div class="col-sm-3" style="width:420px; height:750px; border:1px solid black;" >
<h3>ad</h3>
</div>
    {% endblock %}
<script>
    jQuery('input[name=submit]').on('click', function(){
 if(jQuery(this).hasClass('active')){
   return false;
 }
 else{
  jQuery(this).addClass('active');
 }
});
    </script>
   {% include 'footer.html' %}

Final Edit: hope this is right? any suggestion?

import datetime

class PostCreateView(CreateView):

    model = Post
    form_class = PostForm
    template_name = 'main/add_post.html'

    def form_valid(self, form):

        self.object = form.save(commit=False)
        # any manual settings go here

        #self.object.category = Category.objects.filter(category__in=categories).all()

        self.object.moderator = self.request.user
        self.object.image = extract(self.object.url) 
        self.object.thumbnail = extractt(self.object.content)
        self.object.save()

        if not hasattr(self.request.session['last_submitted']):
            self.request.session['last_submitted'] = datetime.datetime.now()
            return HttpResponseRedirect(reverse('post', args=[self.object.slug]))
        else:
            delta = datetime.datetime.now() - self.request.session['last_submitted']
            if delta.seconds < 60: # assume allow re-submit after 60 seconds
                return http.HttpForbidden() #or some other better message??
            else:
                return HttpResponseRedirect(reverse('post', args=[self.object.slug]))

    @method_decorator(login_required)
    def dispatch(self, request, *args, **kwargs):
        return super(PostCreateView, self).dispatch(request, *args, **kwargs) 

Edit with the solution provided

class PostCreateView(CreateView):

     model = Post
     form_class = PostForm
     template_name = 'main/add_post.html'

     def form_valid(self,form):

        if not hasattr(self.request.session['last_submitted']):
            last_submitted = pickle.dumps(datetime.datetime.now())
            self.request.session['last_submitted'] = last_submitted
            save_it = True
        else:
            last_submitted = pickle.loads(self.request.session['last_submitted'])
            delta = datetime.datetime.now() - last_submitted
            save_it = (delta.seconds > 60) # assume allow re-submit after 60 seconds

        if save_it:
          self.object = form.save(commit=False)
          # any manual settings go here

          #self.object.category =      Category.objects.filter(category__in=categories).all()

          self.object.moderator = self.request.user
          self.object.image = extract(self.object.url) 
          self.object.thumbnail = extractt(self.object.content)
          self.object.save()
          return HttpResponseRedirect(reverse('post', args=[self.object.slug]))
        else:
           # consider redirect as usual, if the user just clicked twice by mistake
           return self.form_invalid(form) # or Http error code

Upvotes: 2

Views: 2855

Answers (2)

Aviah Laor
Aviah Laor

Reputation: 3658

If this is the buttton:

<input type="submit" name="submit" value="submit" id="preventDouble">

With jQuery:

$("#preventDouble").on("submit",function(){
    $(this).unbind("submit");
    $(this).on("submit",function(){return false;});
};

After the first submit, jQuery will attach an event that will cancel further submits.

Note that this event does not check if the form was actually successfully submited to the server.

This may answer your question, but it's a safer and better approach to track multiple submits on the server, e.g. adding a "last_submitted" attribute to the session, and prevent further submits if datetime.datetime.now is less than 1 minute from session.last_submitted:

import datetime
import pickle

def form_valid(self,form):

    if not hasattr(self.request.session['last_submitted']):
        last_submitted = pickle.dumps(datetime.datetime.now())
        self.request.session['last_submitted'] = last_submitted
        save_it = True
    else:
        last_submitted = pickle.loads(self.request.session['last_submitted'])
        delta = datetime.datetime.now() - last_submitted
        save_it = (delta.seconds > 60): # assume allow re-submit after 60 seconds

    if save_it:
      self.object = form.save(commit=False)
      # any manual settings go here

      #self.object.category =      Category.objects.filter(category__in=categories).all()

      self.object.moderator = self.request.user
      self.object.image = extract(self.object.url) 
      self.object.thumbnail = extractt(self.object.content)
      self.object.save()
      return HttpResponseRedirect(reverse('post', args=[self.object.slug]))
    else:
       # consider redirect as usual, if the user just clicked twice by mistake
       return self.form_invalid(form) # or Http error code      

Edit

import datetime
import pickle

class PostCreateView(CreateView):

     model = Post
     form_class = PostForm
     template_name = 'main/add_post.html'

     def form_valid(self,form):

        if not hasattr(self.request.session['last_submitted']):
            last_submitted = pickle.dumps(datetime.datetime.now())
            self.request.session['last_submitted'] = last_submitted
            save_it = True
        else:
            last_submitted = pickle.loads(self.request.session['last_submitted'])
            delta = datetime.datetime.now() - last_submitted
            save_it = (delta.seconds > 60) # assume allow re-submit after 60 seconds

        if save_it:
          self.object = form.save(commit=False)
          # any manual settings go here

          #self.object.category =      Category.objects.filter(category__in=categories).all()

          self.object.moderator = self.request.user
          self.object.image = extract(self.object.url) 
          self.object.thumbnail = extractt(self.object.content)
          self.object.save()
          return HttpResponseRedirect(reverse('post', args=[self.object.slug]))
        else:
           # consider redirect as usual, if the user just clicked twice by mistake
           return self.form_invalid(form) # or Http error code

Upvotes: 1

Diljohn5741
Diljohn5741

Reputation: 434

Not sure your project is using jquery lib or not. if it does try following:

jQuery('input[name=submit]').on('click', function(){
 if(jQuery(this).hasClass('active')){
   return false;
 }
 else{
  jQuery(this).addClass('active');
 }
});

What this will do is check if button is already clicked or not. If it does it won't resubmit the page. If you are not using any client side library then i can change it to Native js.

Upvotes: 0

Related Questions