angle-uparrow-clockwisearrow-counterclockwisearrow-down-uparrow-leftatcalendarcard-listchatcheckenvelopefolderhouseinfo-circlepencilpeoplepersonperson-fillperson-plusphoneplusquestion-circlesearchtagtrashx

Добавление контактной формы на многоязычную страницу с содержанием из базы данных

Когда содержимое страницы поступает из базы данных, вы захотите добавить форму контакта с помощью тега.

28 сентября 2019
post main image
unsplash.com/@nickmorrison

Обновление от 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

Оставить комментарий

Комментируйте анонимно или войдите в систему, чтобы прокомментировать.

Комментарии

Оставьте ответ

Ответьте анонимно или войдите в систему, чтобы ответить.