Django-使用AJAX来“流化”带有注释的查询集的结果

时间:2019-02-22 08:38:16

标签: ajax django django-views

因此,我正在加载模型字段中存在的每个值的计数。一切工作正常,但是每次我对数据库进行更改时,我都必须重新启动服务器,以使更改在前端生效

我认为AJAX可能适合这种情况,但我不知道该怎么做。另外请注意,在查询中我有在模板中使用的注释。

我的看法如下:

def counts(request):
    duplicates = Application.objects.all().filter(is_qualified="awarded").values('school_name').annotate(name_count=Count('school_name'))
    context = {
    'repeated_names' : records,
    'duplicates' : duplicates,
    'title' : 'Disbursement Details',
}

return render(request, 'calculations/list.html', context)

和我的网址为:

path('list/', default_views.counts, name='count_rows'),

最后是我的模板:

<table class="table table-hover" id="disbursement_table">
         <thead class=" wow fadeInLeft">
            <tr>
                <th>#</th>
                <th>School</th>
                <th>Number of Applicants</th>

            </tr>
         </thead>
         <tbody class=" wow fadeInRight" wow-data-duration="2s">

            {% for application in duplicates %}

             <tr class="clickabe-row" data-target="{% url 'dup_detail' application.school_name %}">
                <td>{{ forloop.counter}}</td>
                <td>{{ application.school_name}}</td>
                <td>{{ application.name_count }}</td>
             </tr>

            {% endfor %}

         </tbody>
    </table>

有没有一种方法可以使AJAX每次在数据库中发生更改时定期定期更新{{ application.name_count }}值?

1 个答案:

答案 0 :(得分:1)

我认为您有两种选择:

  1. 使用Channels,这是一个很棒的Django Websockets库:
    • Signals,这是Django的本机功能,可让您知道何时将数据保存到模型中。
    • 然后,您只需要在javascript端实现Websocket通信,这相对简单。

signals.py 示例

@receiver(post_save, sender=CanBusAnalyzerJob, dispatch_uid='update_job_status_listeners')
def update_job_status_listeners(sender, instance, **kwargs):
    '''
    Sends job status to the browser when a Job is modified
    '''
    job_id = instance.job_id
    group_name = 'new-job-' + job_id

    message = {
        'total': instance.job_total,
        'progress': instance.progress,
        'status': instance.status
    }

    channel_layer = channels.layers.get_channel_layer()

    async_to_sync(channel_layer.group_send)(
        group_name,
        {
            'type': 'send_job_progress',
            'text': message
        }
    )

JS代码以测试websocket连接

<script>
  var socket = new WebSocket('ws://' + window.location.host + '/ws/');

  socket.onopen = function() {
    console.log("Websocket connection done!");

    if (socket.readyState == WebSocket.OPEN) {
      setInterval(function() {
        socket.send('Hello World');
      }, 10000);
    }
  };

  socket.onmessage = function(e) {
    var data = JSON.parse(e.data);
    var message = data['message'];
    console.log(data);
  };

  socket.onclose = function(e) {
    console.error('Chat socket closed unexpectedly');
  };
</script>

对我来说这是可行的方法,但是如果您想要快速完成操作,则可以创建一个视图并将其注册到urls.py文件中,该文件将从前端代码每隔X秒调用一次。这将从数据库中获取新数据并已经返回html代码,或者仅返回数据并在JS代码内部对其进行处理。

views.py
此示例还能够接收POST参数,例如和ID(如果需要)(名称在urls.py文件中设置)。如果您只需要获取数据,请删除第三行

class ToggleFavouriteSignalView(View):
    def post(self, request, *args, **kwargs):
        obj_id = kwargs['signal_id']

        try:
            model_obj = CanBusLogAnalyzer.objects.get(id=obj_id)

            new_val = False if model_obj.favourite else True

            model_obj.favourite = new_val
            model_obj.save()

            response_text = 'Success:Signal setted as favourite.' if new_val else 'Info:Signal removed as favourite.'

            return HttpResponse(response_text, status=200)
        except CanBusLogAnalyzer.DoesNotExist:
            return HttpResponse('Error:The object no longer exists in the database.', status=503)
        except Exception:
            return HttpResponse('Error:Please check your internet connection.', status=503)

JS代码

//For authentication purposes
function getCrsfCookie() {
    var cookieValue = null,
        name = 'csrftoken';
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = cookies[i].trim();
            if (cookie.substring(0, name.length + 1) == (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

//Runs every 5 seconds
setInterval(function() {
    var csrfcookie = getCrsfCookie();

    var xhttp = new XMLHttpRequest();

    xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 503) {
            alert("Error when trying to toggle favourite!")
        }
    };

    url_arr = window.location.href.split("/")
    base_url = url_arr[0] + "//" + url_arr[2]

    var params = 'signal_id=' + signal_id;
    xhttp.open('POST', base_url + destination_url, true);
    xhttp.setRequestHeader('X-CSRFToken', csrfcookie);
    xhttp.send(params);
}, 5000);