Как заполнить поле выбора wtform с помощью mongokit/pymongo?

Я пытаюсь создать SelectField с помощью запроса mongodb, но пока мне это не удалось:

# forms.py in blueprint
CATEGORIES = []
for item in db.Terms.find():
    CATEGORIES.append((item['slug'], item['name']))


class TermForm(Form):
    category = SelectField(
        choices=CATEGORIES,
        validators=[Optional()])

Но я получаю исключение:

Traceback (most recent call last):
  File "/home/one/Projects/proj/manage.py", line 14, in <module>
    app = create_app(os.getenv('FLASK_CONFIG') or 'default')
  File "/home/one/Projects/proj/app/__init__.py", line 27, in create_app
    from app.term.models import Term, TermCategory
  File "/home/one/Projects/proj/app/term/__init__.py", line 5, in <module>
    from . import views
  File "/home/one/Projects/proj/app/term/views.py", line 7, in <module>
    from .forms import TermForm, CategoryForm
  File "/home/one/Projects/proj/app/term/forms.py", line 48, in <module>
    for item in db.Terms.find():
  File "/home/one/.venv/proj/lib/python3.4/site-packages/flask_mongokit.py", line 238, in __getattr__
    self.connect()
  File "/home/one/.venv/proj/lib/python3.4/site-packages/flask_mongokit.py", line 196, in connect
    host=ctx.app.config.get('MONGODB_HOST'),
AttributeError: 'NoneType' object has no attribute 'app'

Если бы кто-нибудь мог пролить немного больше света на эту тему, я был бы очень признателен.


person eneepo    schedule 25.01.2015    source источник


Ответы (2)


См. нижнюю часть этого ответа для того, что вы действительно хотите, этот первый раздел просто объясняет непосредственную ошибку, которую вы получаете.


Вы запускаете код, который зависит от контекста приложения вне такого контекста. Вам нужно будет запустить код, который заполняет CATEGORIES внутри контекста приложения, чтобы база данных Flask-MongoKit могла получить соединение.

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

Поместите код внутрь функции, затем импортируйте и вызовите эту функцию на фабрике в контексте.

# forms.py

CATEGORIES = []

def init():
    for item in db.Terms.find():
        CATEGORIES.append((item['slug'], item['name']))

# add to create_app function (even the import)

def create_app(conf):
    #...
    from app.term import forms

    with app.app_context():
        forms.init()
    #...

Если вы используете схемы, вы можете добавить функцию, которая выполняется при регистрации схемы, поэтому фабрике приложений не нужно знать обо всех деталях. Переместите все импорты, такие как views, внутрь этой функции регистрации. Изменения сверху не нужны.

# at the bottom of app/term/__init__.py
# assuming blueprint is called bp

@bp.record_once
def register(state):
    with state.app.app_context():
        from . import forms, views

Однако ни один из них, вероятно, не является тем, что вам фактически нужно в данном случае. Похоже, вы пытаетесь динамически установить варианты выбора для поля формы на текущие значения в базе данных. Если вы сделаете это так, как сейчас, оно будет заполнено один раз при запуске приложения, а затем никогда не изменится, даже если записи базы данных изменятся. Что вам действительно нужно сделать, так это установить варианты выбора в методе __init__ формы.

class TestForm(Form):
    category = SelectField()

    def __init__(self, *args, **kwargs):
        self.category.kwargs['choices'] = [(item['slug'], item['name']) for item in db.Terms.find()]
        Form.__init__(self, *args, **kwargs)
person davidism    schedule 25.01.2015

Похоже, вы вызываете метод, которому нужен контекст приложения (db.Terms.find), но контекст не доступен. Вместо этого вы можете заполнить варианты в представлении:

# forms.py
class TermForm(Form):
    category = SelectField(validators=[Optional()])


# views.py
form = TermForm()
form.category.choices = [(item['slug'], item['name']) for item in db.Terms.find()]
person nathancahill    schedule 25.01.2015