Django обновляет HTML-таблицу с помощью AJAX

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

Не обращайте внимания на повторный вопрос.

У меня есть простая таблица HTML с некоторыми данными, и мне просто нужно обновить данные, когда они изменились, не обновляя их.

У объекта есть поле is_locked, и мне нужно сделать следующее: когда объект заблокирован (is_locked=True), отображается маленький значок шкафчика. Я могу сделать все это, но после ручного обновления, что не очень хорошо.

Поэтому, когда пользователь блокирует объект, после перенаправления (обновления страницы) отображается значок шкафчика. Но мне это нужно в режиме реального времени, поэтому, когда два пользователя одновременно смотрят на одну и ту же таблицу, после блокировки объекта (от одного пользователя) этот значок должен отображаться в браузере другого пользователя без обновления страница.

Мне просто нужно, чтобы этот «дополнительный» контент (значок шкафчика) отображался в режиме реального времени, когда пользователь блокирует объект.

Попробуйте игнорировать пользовательские имена (они не на английском языке)


Мои модели.py:

from django.db import models

class OpportunityList(models.Model):
    name = models.CharField(max_length=30, blank=True)
    address = models.CharField(max_length=100, blank=True)
    age = models.IntegerField(blank=True, null=True)
    is_locked = models.BooleanField(blank=True, null=True)
    ...

просмотры.py :

from django.http import JsonResponse
from django.shortcuts import render

from .models import OpportunityList
...
@login_required(login_url='registration/login')
def OptikaList(request):
    optika = OpportunityList.objects.all().filter(opp_type='optika')
    context = {
        'optika': optika
    }

    if request.is_ajax():
        data = {'rendered_table':render_to_string('opportunity/get_more_tables.html', context=context)}
        return JsonResponse(data)

    return render(request, 'opportunity/opp_optika.html', context)


def updateTable(request):
    qs = OpportunityList.objects.all().values()
    return JsonResponse({'users': list(qs)})

urls.py:

from django.urls import path
from .views import *

urlpatterns = [
    ...
    path('optika/', OptikaList, name='optika'),
    path('ajax/update/', update_table, name='update_table'),
    ...

opp_optika.html, где находится таблица, с помощью ajax-скрипта.

{% extends 'base.html' %}
{% load static %}
{% block title %} Optika {% endblock %}
{% block content_row %}

    {% if messages %}
        {% for message in messages %}
            <div class=" container-fluid alert alert-success alert-dismissible" role="alert">
                <button type="button" class="close" data-dismiss="alert">&times;</button>
                <h4 class="alert-heading">Uspešno!</h4>
                <hr>
                <p class="mb-0">{{ message }}</p>
            </div>
        {% endfor %}
    {% endif %}

    <div class="card-body">
        <div class="table-responsive">
            <table class="table table-bordered table table-hover dt-responsive" id="dataTable">
                {% include 'opportunity/opp_breadcrumb.html' %}
                <h2 style="margin-left: 50%;">OPTIKA</h2>

                <thead>
                <tr>
                    <th>Adresa Korisnika</th>
                    <th>Područje</th>
                    <th>Korisnik</th>
                    <th>TIS</th>
                    <th>Napomena</th>
                    <th>Akcije</th>
                    <th style="width: 5px">STATUS</th>
                </tr>
                </thead>
                <tbody>
                {% for opp in optika %}
                    <tr>
                        <td>{{ opp.optika_korisnik_adr }}</td>
                        <td>{{ opp.oppc_place }}</td>
                        <td>{{ opp.optika_korisnik }}</td>
                        <td>{{ opp.optika_korisnik_tis_id }}</td>
                        <td>{% if opp.oppc_comment %}{{ opp.oppc_comment }}{% else %}Bez napomene{% endif %}</td>
                        <td>
                            <button type="button" class="btn btn-success btn-sm" data-toggle="modal"
                                    data-target="#detalji_modal{{ opp.pk }}">
                                Detalji
                            </button>
                        </td>
                        <td>
                            {% if opp.is_locked %}
                                <form action="{% url 'opportunity:delete_locked' opp.pk %}" method="POST"
                                      style="display: table-cell">
                                    {% csrf_token %}
                                    <button class="btn"><i style="width: 50px;color: red" class="fa fa-lock"
                                                           aria-hidden="true"></i></button>
                                </form>
                            {% endif %}
                        </td>
                    </tr>
                    <!------------------------------------- DETALJIMODAL ---------------------------------------------->
                    <div class="modal fade bd-example-modal-lg" tabindex="-1" role="dialog"
                         id="detalji_modal{{ opp.pk }}"
                         aria-labelledby="detalji_modalLabel">
                        <div class="modal-dialog modal-lg" role="document">
                            <div class="modal-content">
                                <div class="modal-header">
                                    <h5 class="modal-title" id="detalji_modalLabel">Detalji</h5>
                                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                                        <span aria-hidden="true">&times;</span>
                                    </button>
                                </div>
                                <div class="modal-body" id="">
                                    <div class="container-fluid">
                                        <h5>{{ opp.optika_korisnik }}</h5>
                                        <p>{{ opp.optika_korisnik_adr.title }}</p>
                                        <p>Broj linije : {{ opp.optika_broj_linije }}</p>
                                        <p>Kontakt : {{ opp.optika_kontakt_tel1 }}</p>
                                        <hr>
                                        <p>Okvirni Datum : {{ opp.optika_instal_okvirni_datum }}</p>
                                        <p>TIS Posla : {{ opp.optika_posao_tis_id }}</p>
                                        <p>Zahtev Info : {{ opp.optika_zahev_uneo }}</p>
                                        <hr>
                                        <p>Datum Unosa : {{ opp.optika_zahtev_datum_unosa }}</p>
                                        <hr>
                                        <p>Napomena : <br> <br>
                                            {% if opp.oppc_comment %} {{ opp.oppc_comment }} {% else %} Nema
                                                napomene za korisnika {{ opp.optika_korisnik|title }}. {% endif %}
                                        </p>
                                    </div>
                                </div>
                                <div class="modal-footer">
                                    <p style="margin-right: auto">Zahtev uneo/la : {{ opp.optika_zahev_uneo }}</p>
                                    {% if not opp.is_locked %}
                                        <form action="{% url 'opportunity:poziv' opp.pk %}" method="POST">
                                            {% csrf_token %}
                                            <button type="submit" name="poziv" class="btn btn-outline-danger">
                                                Poziv
                                            </button>
                                        </form>
                                    {% endif %}
                                    {% if opp.is_locked %}
                                        <form action="{% url 'opportunity:delete_locked' opp.pk %}" method="POST"
                                              style="display: table-cell">
                                            {% csrf_token %}
                                            <button type="submit" class="btn btn-dark">
                                                <i class="fas fa-lock-open"></i>
                                                Otključaj
                                            </button>
                                        </form>
                                    {% endif %}
                                    <button type="button" class="btn btn-outline-primary" data-dismiss="modal">
                                        Zatvori
                                    </button>
                                </div>
                            </div>
                        </div>
                    </div>
                    <!------------------------------------ DETALJI ENDMODAL ------------------------------------------->
                {% endfor %}
                </tbody>
            </table>
        </div>
        <script>
            $(document).ready(function () {
                setInterval(function () {
                    $.ajax({
                        url: '{% url 'opportunity:optika' %}',
                        type: "get",
                        cache: true,
                        dataType: 'html',
                        success: function (data) {
                            console.log("success");
                            $('#dataTable').html(data.rendered_table);
                        },
                        error: function (data) {
                            alert("Got an error dude " + data);
                        }
                    });
                }, 5000);
            });
        </script>
{% endblock content_row %}

get_more_tables.html :

<tr>
    <th>Adresa Korisnika</th>
    <th>Područje</th>
    <th>Korisnik</th>
    <th>TIS</th>
    <th>Napomena</th>
    <th>Akcije</th>
    <th style="width: 5px">STATUS</th>
</tr>
{% for opp in optika %}
    <tr>
        <td>{{ opp.optika_korisnik_adr }}</td>
        <td>{{ opp.oppc_place }}</td>
        <td>{{ opp.optika_korisnik }}</td>
        <td>{{ opp.optika_korisnik_tis_id }}</td>
        <td>{% if opp.oppc_comment %}{{ opp.oppc_comment }}{% else %}Bez napomene{% endif %}</td>
        <td>
            <button type="button" class="btn btn-success btn-sm" data-toggle="modal"
                    data-target="#detalji_modal{{ opp.pk }}">
                Detalji
            </button>
        </td>
        <td>
            {% if opp.is_locked %}
                <form action="{% url 'opportunity:delete_locked' opp.pk %}" method="POST"
                      style="display: table-cell">
                    {% csrf_token %}
                    <button class="btn"><i style="width: 50px;color: red" class="fa fa-lock"
                                           aria-hidden="true"></i></button>
                </form>
            {% endif %}
        </td>
    </tr>
    <!------------------------------------- DETALJIMODAL ---------------------------------------------->
    <div class="modal fade bd-example-modal-lg" tabindex="-1" role="dialog"
         id="detalji_modal{{ opp.pk }}"
         aria-labelledby="detalji_modalLabel">
        <div class="modal-dialog modal-lg" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="detalji_modalLabel">Detalji</h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>
                <div class="modal-body" id="">
                    <div class="container-fluid">
                        <h5>{{ opp.optika_korisnik }}</h5>
                        <p>{{ opp.optika_korisnik_adr.title }}</p>
                        <p>Broj linije : {{ opp.optika_broj_linije }}</p>
                        <p>Kontakt : {{ opp.optika_kontakt_tel1 }}</p>
                        <hr>
                        <p>Okvirni Datum : {{ opp.optika_instal_okvirni_datum }}</p>
                        <p>TIS Posla : {{ opp.optika_posao_tis_id }}</p>
                        <p>Zahtev Info : {{ opp.optika_zahev_uneo }}</p>
                        <hr>
                        <p>Datum Unosa : {{ opp.optika_zahtev_datum_unosa }}</p>
                        <hr>
                        <p>Napomena : <br> <br>
                            {% if opp.oppc_comment %} {{ opp.oppc_comment }} {% else %} Nema
                                napomene za korisnika {{ opp.optika_korisnik|title }}. {% endif %}
                        </p>
                    </div>
                </div>
                <div class="modal-footer">
                    <p style="margin-right: auto">Zahtev uneo/la : {{ opp.optika_zahev_uneo }}</p>
                    {% if not opp.is_locked %}
                        <form action="{% url 'opportunity:poziv' opp.pk %}" method="POST">
                            {% csrf_token %}
                            <button type="submit" name="poziv" class="btn btn-outline-danger">
                                Poziv
                            </button>
                        </form>
                    {% endif %}
                    {% if opp.is_locked %}
                        <form action="{% url 'opportunity:delete_locked' opp.pk %}" method="POST"
                              style="display: table-cell">
                            {% csrf_token %}
                            <button type="submit" class="btn btn-dark">
                                <i class="fas fa-lock-open"></i>
                                Otključaj
                            </button>
                        </form>
                    {% endif %}
                    <button type="button" class="btn btn-outline-primary" data-dismiss="modal">
                        Zatvori
                    </button>
                </div>
            </div>
        </div>
    </div>
    <!------------------------------------ DETALJI ENDMODAL ------------------------------------------->
{% endfor %}

person dev.ink    schedule 08.01.2020    source источник


Ответы (1)


У вас есть ряд проблем в вашем коде.

Что делает ваш текущий вызов AJAX: он вызывает ваше представление displayUser. Это представление отображает весь шаблон crud.html (включая javascript!) и возвращает его. Ваш javascript помещает это в указанное вами место. Итак, после первого вызова AJAX у вас есть структура вложенной таблицы с двумя блоками javascript, которые работают параллельно.

И затем эти две функции снова начинают вызывать представление, получая полностью отрендеренные страницы. Таким образом, через некоторое время вы получите запутанную веб-страницу с несколькими параллельно работающими скриптами, размещающими полностью отрисованные страницы повсюду. Это наверняка съест память.

Что вы можете сделать, так это проверить, является ли ваш request запросом ajax, и в этом случае отображать только внутреннюю таблицу и возвращать ее обратно в ваш javascript:

def displayUser(request):
    users = CrudUser.objects.all()
    context = {
        'users': users
    }

    if request.is_ajax():
        data = {'rendered_table': render_to_string('table_contents.html', context=context)}
        return JsonResponse(data)

    return render(request, 'crud.html', context) 

Подшаблон для внутренней таблицы:

# table_contents.html
<tr>
    <th>Name</th>
    <th>Address</th>
    <th>Age</th>
</tr>
{% for user in users %}
    <tr>
        <td>{{ user.name }}</td>
        <td>{{ user.address }}</td>
        <td>{{ user.age }}</td>
    </tr>
{% endfor %}

Теперь вы можете поместить это в свой шаблон в свой javascript.

$('#_appendHere').html(data.rendered_table);

Последнее замечание: я думаю, что в вашей функции ajax должно быть data_type, а не dataType.

person Chris    schedule 08.01.2020
comment
Отлично, это действительно помогло. Но сейчас, когда я пытаюсь реализовать это в реальном проекте, кажется, что ничего не происходит. Я получаю сообщение «успех» из журнала консоли из ajax, но когда я блокирую объект, этот значок шкафчика не появляется в таблице. После того, как я обновляю страницу вручную, она появляется. Я отредактировал свой код до фактической версии. - person dev.ink; 08.01.2020
comment
Я посмотрю ваш код. Вежливое замечание: ИМХО, было бы лучше опубликовать ваш новый вопрос как новый вопрос, а не менять исходный вопрос: теперь текущий ответ не отражает ваш текущий вопрос. - person Chris; 08.01.2020
comment
Да, извините за это. Я понял это, когда перезаписал оригинал :( - person dev.ink; 08.01.2020
comment
Можете ли вы откатить свое редактирование до предыдущей версии? Я думаю, что можно отменить свои собственные правки, щелкнув ссылку «отредактировано» в своем сообщении. - person Chris; 08.01.2020
comment
Конечно я могу. Я сейчас на телефоне, так что сделаю это позже. А пока могу я вежливо попросить вас пересмотреть это? ^^ - person dev.ink; 08.01.2020
comment
я посмотрю на это - person Chris; 08.01.2020
comment
Давайте продолжим обсуждение в чате. - person Chris; 08.01.2020
comment
Я только что удалил один из своих вопросов и потерял свою репутацию, и теперь я не могу получить доступ к чату -.- Не могу в это поверить.. - person dev.ink; 13.01.2020
comment
Я попытаюсь скопировать свои последние комментарии вашему представителю git. - person Chris; 13.01.2020