Рендеринг во вложенном операторе Jinja2 в html-файле

Источником моей проблемы является функция проверки формы, которая определяется как:

def AirlineICAORequired():
    """
    Validates whether string is a valid ICAO code
    """
    message = '''Must be an airline ICAO code. Please refer to: <a id = "err-icao" href = "{{ url_for('api.airlines') }}" class = "link-danger">List of Airlines</a> for a list of airlines with ICAO codes listed.'''

    def _airlineicao(form, field):
        airline = get_airline(field.data)
        
        if not airline:
            raise ValidationError(message)
    return _airlineicao

Обратите внимание, что я отображаю HTML-тег, в который пытаюсь отобразить URL-адрес маршрута «api.airlines». Мне нужно рассмотреть следующий вопрос:

  1. Я не могу использовать app_context ни из from flask import current_app, ни из фактического экземпляра приложения, определенного как app из app.py, по следующим двум причинам:

    а) with current_app.app_context():... по-прежнему будет вызывать ошибку RuntimeError, в которой говорится, что я работаю вне контекста приложения.

    б) Если я попытаюсь импортировать from app import app в файл, в котором находится функция (forms.py), то столкнусь с циклической ошибкой импорта, поскольку другие файлы, такие как Routes.py (который имеет Blueprint и импортируется в app. py) импортировать из этого файла.

В html-файле я загружаю сообщение об ошибке как:

{% for error in initializer_form.initializer.errors %}
<li class = "list-group-item list-group-item-danger">
 {{ error|safe }}
</li>
{% endfor %}

к сожалению, это приводит к следующим строкам html:

<li class = "list-group-item list-group-item-danger">
    Must be an airline ICAO code. Please refer to: <a id = "err-icao" href = "{{ url_for('api.airlines') }}" class = "link-danger">List of Airlines</a> for a list of airlines with ICAO codes listed.
</li>

В контексте initializer_form — это форма, в которой тот же валидатор настроен для проверки.

Также вот изображение того, как это выглядит на веб-сайте, внизу показан URL-адрес для перенаправления, если нажать «Список авиакомпаний»:

Другая полезная информация:

Структура файла проекта с показанными соответствующими файлами:

routelookup/
├─ Config/
├─ data/
├─ static/
├─ templates/
├─ api.py
├─ app.py
├─ form.py
├─ routes.py

Импорт (для всех файлов импорт находится в верхней части файла):

приложение.py:

# imports
from flask import Flask
from routes import routes
from api import api
from routeparser import reset_contents, fr_api_logout
from Config import config
import atexit

форма.py:

# imports
from flask_wtf import FlaskForm
from routeparser import get_airline
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import InputRequired, Email, Length, ValidationError

маршруты.py:

# Imports
from flask import Blueprint, render_template, redirect, url_for
from pathlib import Path
from forms import AirlineInitForm

Что я хочу

Если я хочу получить правильный URL-адрес в href, а не так, как показано выше, с помощью изображения и второго блока кода html, как я могу подойти к этому, учитывая проблему, которая у меня есть, и хочу ли я сделать это, используя url_for или что-то близкое к этому это без жесткого кодирования?

Редактировать 1

Дата: 2.10.23

Я создал новый файл под названием form_validators, который частично показан ниже:

# imports
from flask import url_for
from app import app
from routeparser import get_airline
from wtforms.validators import ValidationError

# Relavant validator to the issue
def AirlineICAORequired():
    """
    Validates whether string is a valid ICAO code
    """
    with app.app_context():
        message = f'''Must be an airline ICAO code. Please refer to: <a id = "err-icao" href = "{url_for('api.airlines') }" class = "link-danger">List of Airlines</a> for a list of airlines with ICAO codes listed.'''

    def _airlineicao(form, field):
        airline = get_airline(field.data)
        
        if not airline:
            raise ValidationError(message)
    return _airlineicao

все валидаторы были перемещены в этот файл с соответствующим импортом.

В forms.py добавлен только импорт:

from form_validators import AtLength, AirlineICAORequired

Вам нужно показать структуру файлов и то, как вы выполняете импорт. Вы сможете решить проблему циклического импорта, если правильно отделите функции валидатора от маршрутов. Похоже, что в одном из ваших файлов произошел непреднамеренный импорт.

PGHE 28.09.2023 23:36

@PGHE Я обновил ответ, чтобы, надеюсь, лучше отразить то, что вы сказали.

Sergio Ley 30.09.2023 04:23

Я бы попробовал поместить вашу функцию валидатора в отдельный файл и сделать ее независимой от routes.py и forms.py. В настоящее время, если вы импортируете свой app в forms.py, ваш циклический импорт будет app -> routes -> forms -> app.

PGHE 01.10.2023 23:03

@PGHE не могли бы дать полный ответ на этот вопрос, в том числе сделать его «независимым» от routes.py? Я создал новый файл (form_validators.py), переместил туда всё (необходимый импорт, функции валидатора) и в forms.py импортировал валидаторы из form_validators. Теперь ошибка циклического импорта указывает на routes.py, который использует форму из forms.py.

Sergio Ley 02.10.2023 08:30

Сообщение об ошибке ссылки (отредактировано): Traceback (most recent call last): File "/Users/sergioleylanguren/Desktop/Route Decider/routelookup/forms.py", line 5, in <module> from form_validators import ... File "/Users/sergioleylanguren/Desktop/Route Decider/routelookup/form_validators.py", line 3, in <module> from app import app File "/Users/sergioleylanguren/Desktop/Route Decider/routelookup/app.py", line 7, in <module> from routes import routes ImportError: cannot import name 'routes' from partially initialized module 'routes' (most likely due to a circular import)

Sergio Ley 02.10.2023 08:30

вероятно, потому, что порядок импорта: app -> routes -> form -> form_validators -> app. и если бы я попытался импортировать current_app в form_validators, я бы снова получил ошибку вне контекста позже, как описано выше в теле в 1.a

Sergio Ley 02.10.2023 18:39
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Введение в CSS
Введение в CSS
CSS является неотъемлемой частью трех основных составляющих front-end веб-разработки.
Как выровнять Div по центру?
Как выровнять Div по центру?
Чтобы выровнять элемент <div>по горизонтали и вертикали с помощью CSS, можно использовать комбинацию свойств и значений CSS. Вот несколько методов,...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Travel Booking Angular Template один из лучших Travel & Tour booking template in the world. 30+ валидированных HTML5 страниц, которые помогут...
0
6
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Итак, я решил свою проблему. Я хотел бы поблагодарить @PGHE за то, что они помогли мне настолько, насколько могли, и это вдохновило меня глубже вникнуть в мою собственную проблему. Я внес следующие изменения, некоторые из которых можно увидеть в разделе «Правка 1» в тексте выпуска. Подводя итог, я создал новый файл под названием «forms_validators.py», куда я добавлю все пользовательские валидаторы и импортирую их соответственно в «forms.py». Что касается рассматриваемого валидатора, который мне нужно было «исправить», я внес следующие изменения, как показано в блоке кода ниже:

def AirlineICAORequired(msg = None):
    """
    Validates whether string is a valid ICAO code
    """
    # added method to add custom messages
    if isinstance(msg, str):
        message = msg
    else:
        message = "Must be an airline ICAO code. Please double check to make sure it's correct."

    def _airlineicao(form, field):
        airline = get_airline(field.data)
        
        if not airline:
            raise ValidationError(message)
    return _airlineicao

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

Согласно form.py, я удалил импорт: AirlineICAORequired из form_validators.py и внутри формы я добавил метод для добавления валидаторов после добавления поля ввода в форму с установленными валидаторами:

# forms.py, lines 20-26 within class AirlineInitForm
def add_validator_to(self, attr, *args):
    validator_attr = getattr(self, attr)
    
    if hasattr(validator_attr, "validators"):
        validator_attr.validators = validator_attr.validators + list(args)
    else:
        raise AttributeError("Check again if you inputed the correct attribute name.")

Что касается страницы маршрутов, я определил, что смогу использовать url_for без каких-либо проблем с контекстом приложения, а что нет. Таким образом:

@routes.route('/', methods=['GET', 'POST'], subdomain='application')
def main():
    form = AirlineInitForm()

    form.add_validator_to(
        "initializer", 
        AirlineICAORequired(f'''
        Must be an airline ICAO code. Please refer to: <a id = "err-icao" href = "{url_for("api.airlines")}" class = "link-danger">List of Airlines</a> for a list of airlines with ICAO codes listed.
        ''')
    )
    
    if form.validate_on_submit():
        icao = form.initializer.data

        return redirect(url_for('api.generate', icao=icao), code=307)

    return render_template('main.html', initializer_form=form)

перед проверкой правильности формы (if form.validate_on_submit()) я добавил валидатор (AirlineICAORequired). Мне нужно было добавить его в поле инициализатора с помощью указанного ниже метода, добавленного в класс формы, используя url_for, чтобы получить URL-адрес маршрута API авиакомпании, как я хотел, добавив это в строке f, которая представляет собой сообщение об ошибке, отправляемое в случае неудачной проверки.

Другие вопросы по теме