ListProperty(db.Key)的字段是使用wtforms.ext.appengine.db import model_form创建的表单中跳过的?

时间:2013-04-29 06:15:03

标签: python google-app-engine google-cloud-datastore wtforms

我正在使用model_form从App Engine模型自动创建表单。它工作正常,但创建的表单不包括ListProperty()字段。 代码段:

在models.py中:

class Team(db.Model):

    name = db.StringProperty()
    members = db.ListProperty(db.Key)
在views.py中

def test_app():

    form = model_form(Team)
    app.logger.debug("form :" + str(dir(form)))
    return render_template("some_template.html")

dir(form)未显示字段'members',它是ListProperty()。我不能在模板中使用'form.members',因为表单没有'members'属性。

我在http://wtforms.simplecodes.com/docs/1.0.3/ext.html中看到ListProperty没有等效的'Field'。如何处理这些模型?

1 个答案:

答案 0 :(得分:1)

WTforms没有为App Engine的ListProerty提供等效的“Field”,而model_form正在跳过“members”字段。那么,我们如何在'members'数据存储区域中存储'db.Key'实例。在这个问题上花了很多时间后,我终于能够在成员字段中存储'db.Key'实例。代码片段如下:

models.py:

class Team(db.Model):
    members = db.ListProperty(db.Key)

由于成员存储所有可用成员的“db.Key”实例。显示的表单应该有多个选择字段,以便用户可以选择多个成员。我使用WTforms来做到这一点。

forms.py:

class TeamForm(wtf.Form):
    members = wtf.SelectMultipleField('Members', validators=[validators.Required()])

views.py:

class create_team():
    form = TeamForm()
    form.members.choices = [(u.key(), u.name) for u in Member.all().order('name')]
    return render_template("create_team.html", form=form)

HTML只是呈现表单字段。现在,如果您尝试保存表单,则会收到错误“'sdjfsjdfks23746jhew874'不是此字段的有效选择”。我深入研究WTforms代码,打开wtforms / fields / core.py。

class SelectMultipleField(SelectField):
    """ 
    No different from a normal select field, except this one can take (and
    validate) multiple choices.  You'll need to specify the HTML `rows`
    attribute to the select field when rendering.
    """
    widget = widgets.Select(multiple=True)

    def iter_choices(self):
        for value, label in self.choices:
            selected = self.data is not None and self.coerce(value) in self.data
            yield (value, label, selected)

    def process_data(self, value):
        try:
            self.data = list(self.coerce(v) for v in value)
        except (ValueError, TypeError):
            self.data = None

    def process_formdata(self, valuelist):
        try:
            self.data = list(self.coerce(x) for x in valuelist)
        except ValueError:
            raise ValueError(self.gettext('Invalid choice(s): one or more data inputs could not be coerced'))

    def pre_validate(self, form):

        if self.data:
            values = list(c[0] for c in self.choices)
            for d in self.data:
                if d not in values:
                    raise ValueError(self.gettext("'%(value)s' is not a valid choice for this field") % dict(value=d))

正如您所看到的,预验证功能正在抛出该错误。 self.choices包含您在views.py中提供的所有选项,其中包含[(db.Key instance,member name),...]。 db.Key实例是将以unicode的形式发送到html表单的实例。因此,self.data包含每个db.Key实例的unicode值列表。这就是为什么

if d not in values:

满足此条件,因此引发异常。为了使它工作,我改变了pre-validate()函数如下(我不知道还有什么做)

def pre_validate(self, form):

    if self.data:
        values = list(unicode(c[0]) for c in self.choices)
        for d in self.data:
            if d not in values:
                raise ValueError(self.gettext("'%(value)s' is not a valid choice for this field") % dict(value=d))

现在,在views.py函数中将表单日期存储在数据存储区中。使用此:

members = [db.get(data).key() for data in form.members.data if data]

将unicode转换为'db.Key'实例。希望它对某人有所帮助,如果有更好的方法请告诉我。