Django - проблема вызова функции в шаблонах и возвращения рендеринга значения этой функции на той же странице

У меня есть страница, которая отображает список объектов из моей базы данных. Мне нужно нажать кнопку, которая запрашивает в моей базе данных конкретный объект, выполняет какие-то действия в моих представлениях и возвращает значение цены, которое я хотел бы отобразить на этой же странице во всплывающем окне, без перезагрузки, вместо Текст наполнителя у меня есть. Я попытался сделать это, создав форму с кнопкой, которая имеет объект id в поле значения и отправив это значение в представление моей исходной страницы, а затем я вызываю функцию, которая обрабатывает то, что я хочу сделать с этим идентификатором. Я запрашиваю объект id, передайте его новой функции просмотра, запросите мою базу данных и попробуйте вернуть значение. Я делаю if request.POST утверждение в представлении исходной страницы t, и измените отображаемую переменную на новое значение, которое я хочу отобразить. Когда я нажимаю кнопку, я получаю тот же текст заполнителя во всплывающем окне и в консоли получаю следующую ошибку:

ValueError: The view engine.views.search_list didn't return an HttpResponse object. It returned None instead.

Так что, похоже, мне приходится возвращать HTTP-запрос всякий раз, когда я вызываю функцию представления. Я попытался вернуть обработанный ответ в новой функции просмотра и после проверки if request.POST и передал новое значение в качестве контекста:

return render(request, 'original_page.html', {'value':new_value})

Я получаю ту же ошибку. Как я могу вернуть нужное значение на той же странице, не получая эту ошибку? Я пытался использовать HttpResponse с пустым значением, и redirect('some_place.html') безуспешно У меня есть Iframe, который останавливает перезагрузку моей HTML-страницы. Вот код, который я использую:

HTML

<iframe name="submit-frame" style="display: none"></iframe>
 <form action="{% url 'search_list' %}" method="post" target="submit-frame">{% csrf_token %}
     <button name="productId" value="{{product.id}}" data-toggle="popover" data-animation="true"  data-content="{{price}}"  type="" id='button'>Reveal Price</button>
 </form>

<script type="text/javascript">
 $('[data-toggle="popover"]').popover({
    container: 'body',
     delay: { "show": 100, "fade": 100 },
})

</script>

Views - функция для получения нового значения

def get_price(request):
    product_id = request.POST.get('productId')
    item = get_object_or_404(Product, id=product_id)
    price = item.price
    return price

Представления - Оригинальное Представление Представления

def search_list(request):
results = Product.objects.all().order_by('name')
price = 'no_price'
if request.POST:
    print(request.POST.get('productId'))
    tcg_price = get_price(request)
    return render(request, 'search_result_list.html', {'tcg_price': tcg_price})
else: ...
return render(request, 'search_result_list.html', {'price': price, 'results':results})

1 ответ

То, что вы пытаетесь сделать, обычно обрабатывается с помощью асинхронного вызова (AJAX). То, как вы сейчас настраиваете, форма отправляется, и страница перезагрузится. Это не удобный для пользователя способ, а "Web 1.0" способ делать вещи (также, iframes... тьфу!). Вот как я бы изменил ваши настройки:

Новый взгляд

def ajax_get_price(request):
    response = {}
    product_id = request.POST.get('productId')

    try:
        item = Product.objects.get(id=product_id)
        response['price'] = item.price
        response['success'] = True
    except ObjectDoesNotExist:
        response['error'] = "Item not found!"
        response['success'] = False

    return JSONResponse(response)

Новый интерфейсный обработчик

Вы бы отправляли данные в это новое "представление" через вызов AJAX в JavaScript. Я буду использовать jQuery здесь в качестве примера:

$("button[name='productId']").on("click", function() {
    var productID = $(this).val();
    $.ajax({
        'data': {
            'productId': productID
        },
        'type': "POST",
        'url': "{% url 'myproject:ajax_get_price' %}"
    })
    .done(function(json) {
        if(json.success == true) {
            var itemPrice = json.price;
            // TODO: Do something with the price here (show a popup, tooltip, whatever)
        } else {
            if(json.hasOwnProperty('error') {
                // TODO: Show the error
            })
        }
    })
    .fail(function(xhr, status, error) {
        // TODO: Handle this error case also
    });
});

Есть несколько вещей, с которыми вам нужно справиться, помимо этой заглушки:

  • Скорее всего, вам придется обрабатывать токен CSRF (подделка межсайтовых запросов) в beforeSend позвонить $.ajax() в вашем коде JavaScript.
  • Вероятно, вам следует проверить поддельные запросы в вашем представлении (это запрос GET?) И другие подобные крайние случаи.
Другие вопросы по тегам