将 WTForms QuerySelectField 与 Pyramid 1.7 的数据库会话一起使用

Use WTForms QuerySelectField with Pyramid 1.7's db session

我在我的金字塔应用程序中使用 wtforms_sqlalchemy 并定义了几个 QuerySelectField。查询工厂使用导入的 DBSession 对象进行查询。

from wtforms.form import Form
from wtforms_sqlalchemy.fields import QuerySelectField
from myapp.models import DBSession, MyModel

def mymodel_choices():
    choices = DBSession.query(MyModel)
    return choices

class MyForm(Form):
    mymod = QuerySelectField(u'Field', query_factory=mymodel_choices)

Pyramid 1.7 引入了一个新的 SQLAlchemy 脚手架,它将 db 会话对象附加到每个请求。在我看来,使用新的脚手架 mymodel_choices 必须使用 request 才能访问数据库会话。尽管该字段无权访问请求对象,也不知道用它调用工厂。

我的想法是直接从视图更新 query_factory,但这似乎不是一个合乎逻辑的方法。当数据库会话是请求对象的一部分时,如何使用 QuerySelectField

您可以尝试这样的方法(尽管这不是最干净的解决方案)

from myapp.models import MyModel
from pyramid import threadlocal

def mymodel_choices(request=None):
    request = request or threadlocal.get_current_request()
    choices = request.DBSession.query(MyModel)
    return choices

详情请见:http://docs.pylonsproject.org/projects/pyramid/en/latest/api/threadlocal.html

query_factory 仅指定要使用的 default 查询,但是 QuerySelectField will prefer the query property if it is set. 这对 Pyramid 很有用,它不鼓励直接与 threadlocal 交互.

更改工厂以接受数据库会话。将 query 设置为使用请求的数据库会话调用您的工厂的结果。

def mymodel_choices(session):
    return session.query(MyModel)

f = MyForm(request.POST)
f.mymod.query = mymodel_choices(request.db_session)

因为这有点不方便,您可以创建一个 Form 的子类,它采用 request,提取适当的表单数据,并调用每个 QuerySelectField's 查询工厂请求。

class PyramidForm(Form):
    def __init__(self, request, **kwargs):
        if 'formdata' not in kwargs and request.method == 'POST':
            kwargs['formdata'] = request.POST

        super().__init__(**kwargs)

        for field in self:
            if isinstance(field, QuerySelectField) and field.query_factory is not None and field.query is None:
                field.query = field.query_factory(request.db_session)

class MyForm(PyramidForm):
    ...

f = MyForm(request)