Использование графических процессоров Django с формами
У меня есть несколько форм, которые будут показаны везде в моем проекте, и, следовательно, я читал, что лучший способ сделать это с помощью 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)
На самом деле это не работает, если я отправляю неверную форму, она просто возвращается на ту же страницу и не отображает заполненную форму.
Если кто-то может направить меня или перенаправить меня в некоторые документы по этой теме, это было бы потрясающе! Спасибо!
Проблема в том, что ваш процессор создает экземпляр формы для каждого рендеринга. Каждый раз, когда вы вызываете рендер, вызывается ваш процессор, который создает новую форму и отображает форму 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>
================================================== =========================
Я лично считаю, что первое решение является лучшим, но когда вы начинаете усложняться, вы, вероятно, должны перейти ко второму решению, поскольку представления на основе классов упрощают просмотр сложных представлений.
Прямой ответ: вы проверяете форму в 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)
Читайте больше в документации.