Отправить форму обратно и из двух представлений в Django

#python #html #django #django-views #django-forms

Вопрос:

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

Эта последняя часть вызывает у меня проблемы, так как мне удается показать пользователю, как будет выглядеть его файл, но я не смог найти способ вернуть его в исходную форму ввода, откуда он был взят

Предварительный просмотр HTML

 {% extends "encyclopedia/layout.html" %}

{% block title %}
    Encyclopedia
{% endblock %}

{% block body %}
    <h1>Preview</h1>

    <h3>{{title}}</h3>
    <hr>
    
    {{preview|safe}}

    <form action="{% url 'new_entry' %}" method="POST">
        {% csrf_token %}
        <input type="submit" name="return" value="Return">
    </form>

{% endblock %}
 

Новая запись HTML

 
{% block title %}
    Encyclopedia
{% endblock %}

{% block body %}
    <h1>New Entry</h1>
    <div class="form-group">
        <form action="{% url 'new_entry' %} " method="POST">
            {{form.as_table}}
            {% csrf_token %}
            <input type="submit" value="Save" name="submit">
            <input type="submit" value="Preview" name="preview">
        </form>
    </div>
{% endblock %}
 

Просмотры для предварительного просмотра и нового HTML

 def preview(request):
    #Retrieve data from the request
    form = EntryForm(request.POST)
    if form.is_valid():
        title = form.cleaned_data['title']
        body = form.cleaned_data['body']

    # Nonfunctioning part
    #It's supposed to return the request to the original function
    #and letting it know that it has to pre-populate the form
    if 'return' in request.POST:
        return new_entry(request, fill_form=True)

    #Render the contents of the form
    return render(request, "encyclopedia/entry_preview.html",
    {"title":title,"preview":body})


def new_entry(request, fill_form = False): 

    #Non functioning part
    #Supposedly should get the request that the view 'preview'
    #recieved and get the form from there
    form = EntryForm()
    if fill_form is True:
        form = EntryForm(request.POST)

    if form.is_valid():
        title = form.cleaned_data['title']
        body = form.cleaned_data['body']

    #If form returned submit then save the file
    if 'submit' in request.POST:
        util.save_entry(title,body)     
        return redirect(reverse('new_entry'))
    #If form returned preview then call function to display
    #users input rendered correctly     
    elif 'preview' in request.POST:
        #Pass the POST request to this other function
        return preview(request)
    #Else just render an empty form
    else:   
        return render(request,'encyclopedia/new_entry.html',
        {'form':form})
 

Форма основана на модели, она содержит только два основных поля, title и body .

В любом случае открыты другие идеи для решения этой проблемы, моя проблема в основном в том, что при preview вызове функции она отображает переданные значения, но теперь переданные параметры исчезли, и я не могу вернуться к new_entry представлению. Кроме того, я подумал о передаче данных по URL-адресу, но текст может содержать тысячи слов.

Комментарии:

1. Когда пользователь нажимает кнопку «Назад» браузера, он не вызывает вашу функцию просмотра, потому что браузер загружает страницу из истории. Таким образом, вашим пользователям придется перезагрузить страницу. Другое дело, ИМХО, если вы сделаете это таким образом, что разделите окно на две части, и на одной стороне у вас будет форма, на другой у вас будет часть предварительного просмотра, и вы будете отображать предварительный просмотр, пока пользователь пишет. Точно так же, как в переполнении стека. Дайте мне знать, если вы решите сделать это таким образом, я прокомментирую свои советы.

2. На самом деле это звучит даже интереснее, чем то, что я планировал сделать изначально, на самом деле, я выбрал «более простой» путь, просто загрузив проанализированную уценку на новую статическую страницу для простоты. Мне действительно интересно работать с «живой» версией предварительного просмотра, но я понятия не имею, как бы я справился с этим, я использовал Django только для полностью статичных страниц.

Ответ №1:

В продолжение комментариев я кратко объясню один из способов решения этой проблемы. Для этой задачи я бы использовал очень крошечную библиотеку django под названием django_htmx. Просто взгляните на использование htmx, и менее чем через десять минут вы будете готовы с легкостью его реализовать. Ваша форма будет выглядеть примерно так:

 <form action="{% url 'new_entry' %}" 
      data-hx-post="{% url 'new_entry' %}" 
      data-hx-target="#your-container-id"
      data-hx-swap="innerHTML"
      method="POST">
      {{form.as_table}}
      {% csrf_token %}
      <input type="submit" value="Save" name="submit">
      <input type="submit" value="Preview" name="
</form>
 

data-hx-post указывает URL — адрес для публикации этой формы с помощью ajax. И data-hx-target указывает контейнер, в который будет вставлен ответ на запрос ajax. data-hx-swap говорит htmx вставить ответ в этот контейнер.

Поместите свой encyclopedia/entry_preview.html шаблон в блок включения. И включите его на той же странице, что и форму. Не забудьте указать идентификатор элемента контейнера, чтобы вы могли использовать его в htmx data-hx-target . В своей функции просмотра вы можете сказать:

 def new_entry(request, fill_form = False): 
    if request.method == "POST":
        if request.htmx:
            # The request is made with htmx ajax call...
            # So we render only one side of the page. The display side.
            return render(request, "encyclopedia/entry_preview.html",
                         {"title":title,"preview":body})
       else:
          #render the page normally here. both with form and with preview container.

 

Попробуйте и спросите, не застряли ли вы. У вас будет хорошая динамическая страница редактирования уценки.

PS: Вы можете использовать data-hx-trigger его, чтобы он обновлялся даже во время набора текста. точно так же, как Stackoverflow. 🙂

Комментарии:

1. Классно! Это прекрасно решило мою проблему, а также было действительно легко и интуитивно понятно, документация была аккуратной и понятной. У меня осталась только одна маленькая деталь: способ, которым я обновил предварительный просмотр, заключается в hx-trigger = every 100ms том, что, если бы он у меня был hx-trigger=change , он обновился бы, но только когда я отменил выбор области текста. Мое решение, возможно, не столь эффективно, потому что делает запрос на отправку каждые 100 мс. Возможно, вы могли бы мне в этом помочь. В любом случае, большое спасибо!

2. Может быть, вы можете использовать это: hx-trigger="keyup changed delay:1s" чтобы он публиковал «при вводе ключа, но только в том случае, если значение поиска изменилось и пользователь не вводил ничего нового в течение 1 секунды».