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



我在金字塔应用程序中使用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

query_factory仅指定要使用的默认查询,但如果设置了query属性,QuerySelectField将首选该属性。 这对于金字塔很有用,因为它不鼓励直接与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)

你可以尝试这样的东西(尽管它不是最干净的解决方案(

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

最新更新