Добавление контактной формы на многоязычную страницу с содержанием из базы данных
Когда содержимое страницы поступает из базы данных, вы захотите добавить форму контакта с помощью тега.
Обновление от 11 октября 2019 года: я изменил тег дополнения с '{% дополнения: ... %}' на '[ [... ]]". Причина в том, что я хотел сделать вывод текста страницы, исходящего из базы данных, используя render_template_string, и конфликты '{% ... %}' с Jinja2 тегами. И да, я не хочу реализовывать Jinja2 пользовательские метки.
Что сложного в реализации страницы контакта с формой контакта с Flask и ? WTFormsВы можете найти решения о том, как реализовать страницу контакта, Flask но каждый раз, когда страница представляет собой страницу на одном языке и использует файл Jinja2 шаблона. Так зачем писать об этом сообщение?
Причина в том, что это не так уж просто, когда содержимое страницы может быть многоязычным и поступать из базы данных. У меня есть страница, которую я могу редактировать с помощью администратора, и я хочу, чтобы контактная форма была размещена где-то на странице с помощью тега. Зачем нужна бирка? Потому что мы должны быть в состоянии разместить контактную форму в любом месте содержимого. После замены тега на контактный формуляр его также необходимо обработать при отправке. Полегче? Может быть, для тебя, но не для меня.
Представляя дополнения
Рассматривая другие решения, я подумал, что было бы полезно реализовать контактную форму в качестве дополнения. Почему? Потому что дополнительный модуль - это то, что вы должны иметь возможность легко добавлять к своему контенту. Также должна быть возможность добавить контактную форму на нескольких страницах. Дополнительный модуль включает в себя больше функций, например, дополнительный модуль контактной формы также добавляет администратору функцию контактной формы, с помощью которой мы можем просмотреть отправленные формы.
Внедрение дополнительного модуля
Первое, что я сделал, это определил тег, который идентифицирует дополнительный модуль контактной формы:
{% addon:contact_form,id=87 %}
Это тег, который мы можем добавить к содержимому нашей многоязычной страницы из базы данных. Другие компоненты дополнения к форме контакта:
- ContactForm, модель (таблица)
- Администраторская часть, где мы видим предоставленные формы
А затем нам нужен общий механизм, который обрабатывает дополнения при отображении страницы. Как вы помните из предыдущего сообщения, есть только одна функция, которая генерирует страницу. Поскольку содержимое не меняется, оно кэшируется:
@pages_blueprint.route('/<slug>', methods=['GET', 'POST'])
def page_view(slug):
...
# get content_item
...
# render content_item of get from cache
hit, rendered_content_item = current_app.app_cache.load(cache_item_id)
if not hit:
rendered_content_item = render_template(
...
content_item=content_item,
content_item_translation=content_item_translation,
)
# cache it
current_app.app_cache.dump(cache_item_id, rendered_content_item)
...
return render_template(
...
rendered_content_item=rendered_content_item,
)
Эта функция должна быть изменена и расширена таким образом, чтобы она могла работать с дополнениями.
Преобразование MVC в класс
Например, Flask использование контактной формы очень просто:
@pages_blueprint.route('/contact-form', methods=['GET', 'POST'])
def contact_form():
form = ContactFormForm()
if form.validate_on_submit():
contact_form = ContactForm()
form.populate_obj(contact_form)
db.add(contact_form)
db.commit()
flash( _('Contact form submitted.'), 'info')
return redirect(url_for('pages.thank_you'))
return render_template(
'pages/contact_form.html',
form=form)
И форма обратной связи такая:
class ContactFormForm(FlaskForm):
name = StringField(_l('Name'), validators=[
Length(min=2, max=60),
InputRequired()])
email = StringField(_l('Your email'), validators=[
InputRequired(),
Email()])
message = TextAreaField(_l('Your message'), validators=[
Length(min=6, max=500),
InputRequired()])
submit = SubmitField(_l('Send'))
Мы не можем использовать это здесь, поэтому перепишем это как класс. Я решил вернуть успех или ошибку для GET и POST методов и использовать отдельный метод для получения отрисовываемой контактной формы.
class AddonContactForm:
def __init(self)__:
...
self.errors = False
self.rendered_contact_form = ''
def get_contact_form(self):
self.errors = False
form = ContactFormForm()
self.rendered_contact_form = render_template(
'addons/contact_form.html',
form=form)
return self.errors
def get_rendered_contact_form(self):
return self.rendered_contact_form
def post_contact_form(self):
self.errors = False
form = ContactFormForm()
if form.validate_on_submit():
contact_form = ContactForm()
form.populate_obj(contact_form)
db.add(contact_form)
db.commit()
flash( _('Contact form submitted.'), 'info')
return redirect(url_for('pages.thank_you'))
self.errors = True
self.rendered_contact_form = render_template(
'addons/contact_form.html',
form=form)
return self.errors
Форма ContactFormForm расширяется скрытым параметром, идентифицирующим дополнительный модуль:
addon_id = HiddenField('Addon id')
С помощью этого мы теперь можем изменить функцию page_view:
@pages_blueprint.route('/<slug>', methods=['GET', 'POST'])
def page_view(slug):
...
if request.method == 'POST':
addon_id = None
if 'addon_id' in request.form:
addon_id = request.form['addon_id']
if addon_id is not None:
if addon_id == 'contact_form':
addon_contact_form = AddonContactForm()
if addon_contact_form.process_contact_form():
addon_redirect_url = addon_contact_form.get_redirect_url()
return redirect(addon_redirect_url)
# error(s) found during processing
rendered_contact_form = addon_contact_form.get_rendered_contact_form()
addon_error = True
addon_error_message = addon_contact_form.get_error_message()
....
# addon: processing if '{% addon' found
if '{% addon:' in rendered_content_item:
m = re.findall('\{\%\s*(addon)\s*\:\s*([a-z_]+)\s*.*?\%\}', rendered_content_item)
addon_name = None
if m:
addon_name = m[0][1]
if addon_name == 'contact_form':
if request.method == 'GET':
addon_contact_form = AddonContactForm()
if addon_contact_form.get_contact_form():
rendered_contact_form = addon_contact_form.get_rendered_contact_form()
else:
rendered_contact_form = ''
error = True
error_message = addon_contact_form.get_error_message()
rendered_content_item = re.sub('\{\%\s*(addon)\s*\:\s*([a-z_]+)\s*.*?\%\}', rendered_contact_form, rendered_content_item)
elif request.method == 'POST':
# here we just paste the result from the addon
# typically we only come here when an error was detected in the form
rendered_content_item = re.sub('\{\%\s*(addon)\s*\:\s*([a-z_]+)\s*.*?\%\}', rendered_contact_form, rendered_content_item)
return render_template(
...
)
Резюме
Выше приведено лишь краткое изложение, есть еще кое-что, но я просто хотел рассказать вам об основах. Я также внедрил дополнение FAQ, где нам осталось иметь дело только с GET. Вы можете посетить страницы "Контакты" и "Часто задаваемые вопросы" на этом сайте. Это была всего лишь первая попытка реализовать дополнения, и нет, она не является окончательной. Теперь я должен определить четкий интерфейс всех методов и атрибутов, которые может или должен использовать дополнительный модуль. В другой раз...
Ссылки / кредиты
Exact difference between add-ons, plugins and extensions
https://stackoverflow.com/questions/33462500/exact-difference-between-add-ons-plugins-and-extensions
Intro to Flask: Adding a Contact Page
https://code.tutsplus.com/tutorials/intro-to-flask-adding-a-contact-page--net-28982
Подробнее
Flask Jinja2 Multilanguage WTForms
Недавний
- Скрытие первичных ключей базы данных UUID вашего веб-приложения
- Don't Repeat Yourself (DRY) с Jinja2
- SQLAlchemy, PostgreSQL, максимальное количество строк для user
- Показать значения в динамических фильтрах SQLAlchemy
- Безопасная передача данных с помощью шифрования Public Key и pyNaCl
- rqlite: альтернатива dist с высокой степенью готовности и SQLite
Большинство просмотренных
- Используя Python pyOpenSSL для проверки SSL-сертификатов, загруженных с хоста
- Использование UUID вместо Integer Autoincrement Primary Keys с SQLAlchemy и MariaDb
- Подключение к службе на хосте Docker из контейнера Docker
- Использование PyInstaller и Cython для создания исполняемого файла Python
- SQLAlchemy: Использование Cascade Deletes для удаления связанных объектов
- Flask Удовлетворительный запрос API проверка параметров запроса с помощью схем Маршмэллоу