简体   繁体   English

如何使用mongokit / pymongo填充wtform select字段?

[英]How to populate wtform select field using mongokit/pymongo?

I'm trying to create a SelectField using a mongodb query, but so far I haven't been successful: 我正在尝试使用mongodb查询创建SelectField,但是到目前为止,我还没有成功:

# 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()])

But I get an exception: 但我有一个例外:

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'

If anyone could shed a little more light upon the subject, I would be very appreciative. 如果有人能进一步阐明这个话题,我将非常感激。

It looks like you're calling a method that needs an app context ( db.Terms.find ) without having the context available. 似乎您正在调用需要应用程序上下文( db.Terms.find )且没有可用上下文的方法。 You can populate the choices in the view instead: 您可以改为在视图中填充选择:

# 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()]

See the bottom of this answer for what you really want, this first section is just to explain the immediate error you're getting. 请参阅此答案的底部以获取您真正想要的内容,这第一部分只是为了解释您所遇到的立即错误。


You are running code that depends on an application context outside of such a context. 您正在运行的代码依赖于此类上下文之外的应用程序上下文。 You'll need to run the code that populates CATEGORIES inside an application context so that the Flask-MongoKit db can get a connection. 您需要运行在应用程序上下文中填充CATEGORIES的代码,以便Flask-MongoKit db可以获取连接。

It looks like you're using an application factory, so refactor your code a bit so that you can populate the collection while creating the app (you need access to the app to set up a context). 似乎您正在使用应用程序工厂,因此请稍微重构代码,以便在创建应用程序时可以填充集合(您需要访问该应用程序以设置上下文)。

Put the code inside a function, then import and call that function in the factory within a context. 将代码放入函数中,然后在上下文中在工厂中导入并调用该函数。

# 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()
    #...

If you you're using blueprints, you can add a function that executes when the blueprint is registered, so the app factory doesn't need to know about all the details. 如果您使用的是蓝图,则可以添加一个在注册蓝图时执行的功能,因此应用程序工厂无需了解所有详细信息。 Move all imports such as views to inside this registration function. 将所有导入(例如views移动到此注册功能内。 The changes from above are not needed. 不需要上面的更改。

# 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

However, neither of these are probably what you actually want in this case. 但是,在这种情况下,这些可能都不是您真正想要的。 It looks like you're trying to dynamically set the choices for a form field to the current values in the database. 似乎您正在尝试将表单字段的选择动态设置为数据库中的当前值。 If you do this as you are now, it will be populated once when the app starts and then never change even if the database entries change. 如果您像现在一样执行此操作,则它将在应用程序启动时填充一次,然后即使数据库条目发生更改也不会更改。 What you really want to do is set the choices in the form's __init__ method. 真正想要做的是在表单的__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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM