У меня есть два списка выбора в DOM, первый заполняется во время загрузки URL, когда метод в представлениях загружает страницу. Содержание второго списка выбора зависит от того, что пользователь выбирает в первом списке выбора. Как привязать метод python к событию, когда пользователь делает выбор в первом списке выбора, делать некоторые манипуляции в python, возвращать список значений, которые я хотел бы отобразить во втором списке выбора, а затем заполнять его, не обновляя страницу?

Мой шаблон выглядит так:

{% block content %}

{% if list_of_events %}
    <form>
        <select>
            {% for event in list_of_events %}
                <option value="name">{{ event.module }}</option>
            {% endfor %}
        </select>
    </form>

{% else %}
    <p>No events available now.</p>
{% endif %}

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

{% if first_selection %}
    <form>
        <select>
            {% for room in list_of_rooms %}
                <option value="name">{{ room.id }}</option>
            {% endfor %}
        </select>
    </form>
{% endif %}

<input type="submit" value="Submit">

{% endblock %}

Мой метод views.py выглядит так:

def events(request):
try:
    list_of_events = Event.objects.all()
except:
    raise Http404('Something\'s wrong with events page loader')
return render(request, 'web_service/schedule.html', {
    'list_of_events': list_of_events

})
7
Stan Redoute 27 Авг 2017 в 19:04

3 ответа

Лучший ответ

В Django (по крайней мере, на данный момент) нет прямого способа динамического вызова метода python прямо из шаблона (html) без обновления страницы.

Чтобы вызвать метод python и увидеть его эффект в шаблоне, не обновляя страницу, требуется немного JS. Это не так просто, как вызов метода экземпляра, как в ООП, но не так сложно, как может показаться.

Пример ниже демонстрирует, как реагировать на кнопку click и отправлять некоторые данные в django view, а затем возвращать результат в шаблон без обновления DOM.

Единственный способ вызова кода Python из шаблона - это то же самое, что и url, это означает, что мы должны создать новый url pattern. Затем вызовите необходимый view и верните ответ на шаблон как JsonResponse.

Примечание : обязательно импортируйте jquery внизу тега <body>.

Прежде всего нам нужно создать респондент, который будет обрабатывать нажатие кнопки и создать AJAX запрос на URL, связанный с view. AJAX request передает input в качестве параметра в наш шаблон URL, что означает, что этот параметр будет передан в django view. Если что-то возвращается из нашего вызова view, то данные распаковываются в закрытие success.

Допустим, наш шаблон выглядит так:

<input type="text" id="user-input" autofocus=""><br>
<button type="button" id="sender">Send data</button><br>
<p id="p-text">foo bar</p>

Скрипт обработки кликов и запроса выглядит так:

<script>

$("#sender").click(function () {
    var input = $('#user-input').val();

    $.ajax({
        url: '{% url 'get_response' %}',
        data: {
          'inputValue': input
        },
        dataType: 'json',
        success: function (data) {
          document.getElementById('p-text').innerHTML = data["respond"];
        }
      });
    });

</script>

Новый шаблон необходим в urls.py:

urlpatterns = [
    ...
    url(r'^ajax/get_response/$', views.answer_me, name='get_response')
    ...
]

Примечание: часть URL ajax/ и путь шаблона URL не влияют на то, как обрабатывается этот вызов. Это может быть что угодно, например: ^foo/bar/$.

Последний шаг - добавление отвечающего Django view. Этот простой пример возвращает ввод с некоторым дополнительным текстом, но обычно это место, где вы можете вызывать другие методы Python и делать все, что захотите:

def answer_me(request):
    field = request.GET.get('inputValue')
    answer = 'You typed: ' + field

    data = {
        'respond': answer
            }
    return JsonResponse(data)
7
sadie parker 9 Апр 2019 в 07:16

Вы можете отобразить все возможные вторые списки выбора с display = none, тогда вы можете добавить javascript, например:

function show(select_item) {
        if (select_item == "apple") {
            hiddenDiv.style.visibility='visible';
            hiddenDiv.style.display='block';
            Form.fileURL.focus();
        } 
        else{
            hiddenDiv.style.visibility='hidden';
            hiddenDiv.style.display='none';
        }
    }   
</script>  

<form>
<label>Fruit:</label>
    <select name="Fruit" onchange="java_script_:show(this.options[this.selectedIndex].value)">
        <option value='pear'>pear</option>
        <option value='apple'>apple</option>
        <option value='grapes'>grapes</option>
    </select>

<div id='hiddenDiv' style="display: none;">
    <label>Are you sure you want to eat the apple?</label>
    <select name="AppleQuestion">
        <option value='Yes'>Yes</option>
        <option value='No'>No</option>
    </select>
</div>
</form>

https://codepen.io/metrafull2/pen/WEgWLo попробуйте здесь

1
Mauricio Cortazar 27 Авг 2017 в 16:32

У меня была похожая проблема с OP (принятый ответ наиболее близок к тому, что я нашел), и это был самый популярный результат в моем поиске в Google, поэтому я поделюсь с вами тем, что придумал.

Основным отличием является то, что я установил dataType в 'html' и просто добавил к отображаемому шаблону непосредственно элемент. (если вы не измените dataType, вы получите исключения - не будет работать так, как я реализовал)

//parent_template.html
{% load static %}
<script src="{% static "jquery.js" %}"></script>

{% block first %}
<div class="row">
    {% for x in my_list %}
    <button class="some-filter" id="{{x}}"></button>
    {% endfor %}
</div>
{% endblock first %}

{% block second %}
<div class="row" id="some_id"></div>
{% endblock second %}

<script>
     $(".some-filter").on({
       click: e=> {
           var name = $( e.target )[0].id;
           $.ajax({
             url: '/ajax/info_getter/',
             data: {
               'name': name,
             },
             dataType: 'html',
             success: function (data) {
               if (data) {
                 $("#some_id").html(data);
                 $(".some-filter").removeClass('selected');
                 $( e.target ).addClass('selected');
               }
             }
           });
       }
   })
</script>



// child_template.html
// my big ass template containing lots of image files
{% load static %}
...other stuff

// urls.py
from django.urls import path
from . import views
urlpatterns = [
    ...
    path('ajax/info_getter/', views.info_getter, name='info_getter'),
    ...
]



// views.py
from django.shortcuts import render
...
def info_getter(request):
    name = request.GET.get('name', None)
    if name:
        context["name"] = name

    response = render(request, "child_template.html", context=context)
    return response

Примечание . Я не уверен, считается ли это наилучшей практикой

Примечание : тестируется только на Django 2.2 и Python 3.6.x

1
kt-0 6 Июл 2019 в 18:08