Django - используйте AJAX для «потоковой передачи» результатов набора запросов с аннотациями - PullRequest
0 голосов
/ 22 февраля 2019

Итак, я загружаю счетчики каждого значения, которое существует в поле модели.Все работает нормально, но мне нужно перезагружать сервер каждый раз, когда я делаю изменения в базе данных, чтобы изменения вступили в силу во внешнем интерфейсе .

Я думаю, что 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)

и мои URL-адреса:

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 голосов
/ 22 февраля 2019

На мой взгляд, у вас есть два варианта:

  1. Использовать Каналы , которые являются отличной библиотекой веб-сокетов для Django:
    • Сигналы это встроенная функция Django, которая позволит вам узнать, когда данные были сохранены в модели.
    • Тогда вам просто нужно реализовать связь Websocket на стороне javascript, что относительно просто.

signal.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-код для проверки соединения через веб-сокет

<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, like и 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);
...