#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 секунды».