Kris Tryber
Kris Tryber

Reputation: 237

Updating a Django list view with ajax

I'm having trouble linking this together. I'm trying to build a small leaderboard app. basically users just vote things up or down. I've got everything working except I want the leaderboard itself to update in real time or close to it without having to refresh the page.

I know I need a way to basically get an updated list based on the votes and sort them by highest votes. So I used Django rest to build an API endpoint that produces a response in the order that I want.

The next step would be to use AJAX to get that response. I just can't figure out how to get my new list in place of the old list. I started to write my ajax request and found that I was rewriting my whole HTML template, that can't be right. Could someone provide me some direction? I might just be overthinking this. Maybe I just need an ajax request that refreshes the whole page.

I think I might be having trouble grasping "updating" the HTML classes. I don't need to append or prepend just reorder the given elements.

Or I'm totally overthinking this whole thing so another perspective may be what I need.

View

def streams_list(request):
    streams_ranked = StreamPost.objects.annotate(q_count=Count('upvotes')) \
                                        .order_by('-q_count')
    context = {
        'streams_ranked' : streams_ranked,
        'form': StreamPostForm()
    }
    return render(request, 'streams/index.html', context)

Index.html If I manually refresh this page, it works perfectly.

<div id='stream-list'>
  {% include 'streams/leaderboard_list.html' %}
</div>

leaderboard_list.html

<div class="row">
  <div class="col-md-12">
    {% for stream in streams_ranked %}
      <div class="post-list-box">
        <h1 class="stream-title">{{ stream.title }}</h1>

        <h4 class="stream-description">{{ stream.description }}</h4>

        <a class="btn btn-warning " href="{% url 'streams:detail' pk=stream.pk %}">
        View Stream</a>
        <p>comment area</p>

        <div class="row">
          <div class="col-sm-3 voting-buttons">
            <a class="upvote-btn" data-href='{{ stream.get_api_upvote_url }}'
            href='{{ stream.get_upvote_url }}'><i class="fas fa-thumbs-up"></i></a>

            <span class="upvote-count" data-href="{% url 'streams:vote-count' pk=stream.pk %}">
              {{ stream.upvotes.count }}
            </span>

            <a class="downvote-btn" data-href="{{ stream.get_api_downvote_url }}"
            href='{{ stream.get_downvote_url }}'><i class="fas fa-thumbs-down"></i></a>

            <span class="downvote-count" data-href="{% url 'streams:vote-count' pk=stream.pk %}">
                {{ stream.downvotes.count }}
            </span>
          </div>
        </div>
      </div>
    {% endfor %}
  </div>
</div>

AJAX/JS

$('#stream-list').click(function() {
  $.ajax({
    url: '/',
    method: 'GET',
    data: {},
    success: function(data){
      $('#stream-list').html(data);
    }, error: function(error){
      console.log(error)
      console.log("error")
    }
  })
});

Update Final Working Code

Templates index

<div id='stream-list'>
  <tbody class='table_body'>
  {% include 'streams/leaderboard_list.html' %}
  </tbody>
</div>

leaderboard_list.html

<div class="row">
  <div class="col-md-12">
    {% for stream in streams_ranked %}
      <div class="post-list-box">
        <h1 id="stream-title">{{ stream.title }}</h1>

        <h4 id="stream-description">{{ stream.description }}</h4>

        <a class="btn btn-warning" href="{% url 'streams:detail' pk=stream.pk %}">
        View Stream</a>
        <p>comment area</p>

        <div class="row">
          <div class="col-sm-3 voting-buttons">
            <a class="upvote-btn" data-api-upvote='{{ stream.get_api_upvote_url }}'
            href='{{ stream.get_upvote_url }}'><i class="fas fa-thumbs-up"></i></a>

            <span id="upvote-count" data-upvotes="{% url 'streams:vote-count' pk=stream.pk %}">
              {{ stream.upvotes.count }}
            </span>


            <a class="downvote-btn" data-api-downvote="{{ stream.get_api_downvote_url }}"
            href='{{ stream.get_downvote_url }}'><i class="fas fa-thumbs-down"></i></a>

            <span id="downvote-count" data-downvotes="{% url 'streams:vote-count' pk=stream.pk %}">
                {{ stream.downvotes.count }}
            </span>
          </div>
        </div>
      </div>
    {% endfor %}
  </div>
</div>

JS to control displaying the updated list

var refreshStream = function(){
  var getNewDataUrl = '/streams/'
    $.ajax({
        url: getNewDataUrl,
        method: 'GET',
        data: {},
        success: function(data){
          $('#stream-list').replaceWith($('#stream-list',data));
        },
        error: function(error){
            console.log(error);
            console.log("error");
        }
    });
}

var total_seconds = 5; // refresh every 5 seconds

setInterval(function(){
    refreshStream();
},total_seconds * 1000);

View

def streams_list(request):
    streams_ranked = StreamPost.objects.annotate(q_count=Count('upvotes')) \
                                    .order_by('-q_count')
    context = {
        'streams_ranked' : streams_ranked,
        'form': StreamPostForm()
    }

    return render(request, 'streams/index.html', context)

Upvotes: 3

Views: 4357

Answers (1)

Lemayzeur
Lemayzeur

Reputation: 8525

Use setInterval to refresh the concerned page of HTML every specific second.

var refreshStream = function(){
    $.ajax({
        url: '/url_to_view/',
        method: 'GET',
        data: {},
        success: function(data){
            $('#stream-list').replaceWith($('#stream-list',data));
        },
        error: function(error){
            console.log(error);
            console.log("error");
        }
    });
}

var total_seconds = 5; // refresh every 5 seconds

setInterval(function(){
    refreshStream();
},total_second * 1000);

Keep your view the way it was:

def streams_list(request):
    streams_ranked = StreamPost.objects.annotate(q_count=Count('upvotes')) \
                                    .order_by('-q_count')
    context = {
        'streams_ranked' : streams_ranked,
        'form': StreamPostForm()
    }

    return render(request, 'streams/leaderboard_list.html', context)

Upvotes: 4

Related Questions