Использование графических процессоров Django с формами

62
8

У меня есть несколько форм, которые будут показаны везде в моем проекте, и, следовательно, я читал, что лучший способ сделать это с помощью context_processor. Итак, я создал его внутри своего приложения, и он выглядит примерно так:

def forms_processor(request):

name_form = NewNameForm()
work_form = NewWorkForm()
address_form = NewAddressForm()

context = {'name_form': name_form,
'work_form': work_form,
'address_form': work_form,
}
return context

Это отлично работает, я могу просто использовать {{name_form}} любом месте в своих шаблонах и отображать форму.

Теперь мой вопрос: где я могу проверить форму? В моем views.py или context_processors.py? Сейчас мои взгляды на name_form выглядят примерно так:

def user_profile(request):
if request.method == 'POST':
name_form = NewNameForm(request.POST)

if name_form.is_valid():
form.save()

else:
ctx = {'title': 'Profile', 'active_tab': 'Profile'}

return render (request, 'user_profile.html', ctx)

На самом деле это не работает, если я отправляю неверную форму, она просто возвращается на ту же страницу и не отображает заполненную форму.

Если кто-то может направить меня или перенаправить меня в некоторые документы по этой теме, это было бы потрясающе! Спасибо!

спросил(а) 2021-01-28T02:20:19+03:00 2 месяца, 2 недели назад
1
Решение
87

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

Я бы это сделал, передавая форму, которую вы создаете в представлении, обратно в контекст перед рендерингом. Передайте его в контекстный ключ, такой как "name_form_filled". Затем, если эта переменная присутствует в контексте, не отрисуйте "name_form", вместо этого выведите "name_form_filled".

views.py

def user_profile(request):
ctx = {}
if request.method == 'POST':
name_form = NewNameForm(request.POST)

if name_form.is_valid():
name_form.save() # you named this named_form, not form.
# If you want to redirect to another view when the form is saved successfuly, do it here.
else:
ctx["name_form_filled"] = form

else:
ctx.update({'title': 'Profile', 'active_tab': 'Profile'})

return render (request, 'user_profile.html', ctx)

user_profile.html

<div id="form_container">
{% if name_form_filled %}
<!-- Render form that has input and errors from previous POST. -->
{{ name_form_filled }}
{% else %}
<!-- render empty initial form. User has not attempted to submit yet. -->
{{ name_form }}
{% endif %}
</div>

================================================== =========================

Другой способ, которым вы могли бы это сделать, - превратить это представление в представление, основанное на классе, и наследовать представление на основе базового класса. Этот базовый класс переопределит метод get_context_data и добавит три формы. Обратите внимание, что вы не будете использовать процессор контекста с этой методологией, чтобы избавиться от него, если захотите в этом случае.

Все представления, использующие вашу форму, будут расширять класс базового представления. Затем, после оценки вашей формы, если она недействительна, перезапишите свой контекстный ключ name_form с недопустимым экземпляром формы, который будет в вашем контексте.

views.py

class BaseView(View):
def get_context_data(self, *args, **kwargs):
context = {
"name_form": NewNameForm(),
"work_form": NewWorkForm(),
"address_form": NewAddressForm()
}
return context

class UserProfileView(BaseView):
def get(self, request, *args, **kwargs):
# Do GET logic here.
ctx = self.get_context_data(*args, **kwargs) # BaseView.get_context_data will be called here unless you override it in this class.
ctx.update({'title': 'Profile', 'active_tab': 'Profile'})
return render (request, 'user_profile.html', ctx)

def post(self, request, *args, **kwargs):
# Do POST logic here.
ctx = self.get_context_data(*args, **kwargs) # BaseView.get_context_data will be called here unless you override it in this class.

name_form = NewNameForm(request.POST)

if name_form.is_valid():
name_form.save()
else:
ctx["name_form"] = name_form # will replace the empty form in context with the form instance created in name_form that has input and errors.
return render (request, 'user_profile.html', ctx)

user_profile.html

<div id="form_container">
<!-- Will render whatever is in name_form. If this is after the
user has submitted an invalid form, this form will be populated with input and errors because we overwrote it in the view. -->
{{ name_form }}
</div>

================================================== =========================

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

ответил(а) 2021-01-28T02:20:19+03:00 2 месяца, 2 недели назад
44

Прямой ответ: вы проверяете форму в views.py с is_valid() метода is_valid(). Вам нужно заполнить контекст связанной формой, если форма недействительна:

def user_profile(request):
ctx = {'title': 'Profile', 'active_tab': 'Profile'}

if request.method == 'POST':
name_form = NewNameForm(request.POST)
if name_form.is_valid():
form.save()
return redirect(YOUR_REDIRECT_URL) # Always redirect after successful POST
ctx['form'] = form # if form is invalid return it with context

return render (request, 'user_profile.html', ctx)

Читайте больше в документации.

ответил(а) 2021-01-28T02:20:19+03:00 2 месяца, 2 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема