0

I have a voting template in django. It displays one entry from an SQLite3 database at a time, and when I vote it up or down with a keypress, the vote is saved in the database and the voting template reloads and a new random entry is served up via the view ( a models manager serves up the random entry to the view).

Here is my ideal situation: I would like to have three different entries displayed by the VOTING template.- 3 different key presses would vote on the 3 entries, but they would only refresh their vote count, not the entry text.- 3 different keypresses would select new random entries individually. For now, I am trying it with 1 entry.

The Hard Way: I thought what I should do is pass the id of the voted entry from html to a voting function in views that will then pass the id on to the voting template in views.py for a refresh of the score only and not replacing it with a different entry.

The Simple Way (preferred!): After some more research and looking at the following SO questions:Refresh a div in Django using JQuery and AJAX Reload entire page in Ajax on Django? How to correctly refresh a div using Jquery/Ajax in a Django template Passing list of values to django view via jQuery ajax call ; ,,,,,,

I feel that the crux of the matter is this;

I want to refresh the votes on entries on the voting page when I vote them up. To prevent overkill, I believe that the div updates can be made template side for the vote updates and not switch the entry (which happens when the whole voting.html is reloaded).

To change the entry displayed, can I switch the entry id accessed and refresh the div (get a new entry from the db) when another button is pressed? I thought I would have to pass the entry id to views.py, but perhaps I can do it all in template? I don't need to get a random entry from views if I can just toggle up and down the db entries without error.

To that end I have changed the voting.html code below to include;

                        $.ajax({
                           success: function() {
                           $(this).html();
                       }

after the button press. It allows a vote, but does not refresh the entry. I understand from some SO questions that I have to pass in some values or a div to update, but am having trouble when I do that. I have been trying to pass in the div #Vote, but the script is in the middle of the div, not outside it. Trying to pass in the voteid seems not to work either, and actually prevents voting;

                        $.ajax({      
                           data: {'voteid': text}
                           success: function(data) {
                              $(this).html(data);
                           }
                     });

Can anyone help me to do this?

I feel close - Here is some code snippets;

models.py

class EntryManager(models.Manager): # TO RETURN ONE RANDOM ENTRY
def random(self):      
    random_entries = self.filter(voted = True).order_by('?') # random entry 
    return random_entries[:1] # return latest

voting.html

    <div class = "table">
  <div id="Vote" class = "vote">
  <div style="text-align: left">
  {% for entry in voting_entry_list %} 
    <li><a href="/entries/{{ entry.id }}/">{{ entry.text }}&nbsp{{ entry.score }}</a></li>
    <p>
    <input type="submit" id="voteid" name='voteid' value="{{ entry.id }}" autofocus value="" onfocus="this.value = this.value;" class = "transparent"/>
          <script>
            $(document).ready(function() {
              $("#voteid").bind("keydown", function(e) { //input type=id above
                if (e.keyCode == 38) {
                  var text = $("#voteid").val();        
                  var args = {'voteid':text};       
                  $.get("/voteup/", args).done(function(data) {
                    console.log("message: " + data);
                    //location.reload();
                    $.ajax({
                       success: function() {
                           $(this).html();
                       }
                     });
                  });
                return false;
                }
                if (e.keyCode == 40) {
                  var text = $("#voteid").val();        
                  var args = {'voteid':text};       
                  $.get("/votedown/", args).done(function(data) {
                    console.log("message: " + data);
                    //location.reload();
                    $.ajax({
                       success: function() {
                           $(this).html();
                       }
                     });    
                  });
                return false;
                }       
              });
            });     
          </script>
     {% endfor %}
      </div>
      </div>
  </div>

views.py

def voting(request):
 context = {
  'voting_entry_list': Entry.objects.random(),
 }
 return render(request, 'entries/voting.html', context);  

def voteup(request):
 voting_id = request.GET.get('voteid')
 if request.method=='GET':
    v = Entry.objects.get(pk=voting_id)
    v.score +=1 
    v.voted=True 
    v.save() 
 else:
    pass
 context = {
  'voting_entry_list': v,
  }
 return render('entries/voting.html', {'voting_entry_list': v})

 # not working? no refresh ^
 # Tried these;
 # return render_to_response('voting.html', RequestContext(request, {'voting_entry_list': v})) #no refresh 
 # return render(request, 'entries/voting.html', context); #no refresh
 # return HttpResponse('done') # Only on template reload
 # return render('voting.html', context); #no refresh
 # return HttpResponseRedirect('entries/voting.html') #no refresh
Community
  • 1
  • 1

1 Answers1

1

I don't know why you say Django isn't good for asynchronous requests. It's perfectly fine for those: they are not different in any substantive way from normal ones. For your very simple task, there is no need though for any of this, or any of the tools you mention: you don't want anything asynchronous in the first place.

There are several problems here. Firstly, most of your attempts appear to be rendering the entire voting.html template. That's not what you want, is it: you just want to render a portion, the bit that contains the vote that you want. In addition, you're passing a single vote instance, v, as the "voting_entry_list" context variable, which means that when the template tries to iterate through the list in the for loop, it will raise an exception because a single instance is not iterable. You'd probably find, if you inspected the Ajax response with the browser developer tools, that most of your attempts would have shown that "not iterable" exception.

Then, there are the problems with your Javascript itself. I have absolutely no idea why you have put location.reload() in both your handlers. That causes the entire page to be refreshed, making a whole new - and non-Ajax - request to the server, completely ignoring the Ajax response you already had, and refreshing the whole page. Instead of that, you need to insert the HTML you get in that Ajax response into the appropriate place in the page, via the normal jQuery DOM manipulation functions.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • I have edited my question to clear up the confusions above. All of the code above works fine, just not in the exact way I want. The ajax is in the index.html, and refreshes the content just fine when votes go in. The voting_entry_list is a misnomer, a naming legacy from the other lists I have, it is really just a single entry as you can now see from models.py above........................................................................I agree that I want to get rid of the location reloads,.............Your comments encourage me that what I am trying to do is simple, but what would you suggest? – Helmut Applebaum Aug 09 '14 at 04:19