使用GAE和WTForms进行HTTP POST

2 投票
2 回答
1462 浏览
提问于 2025-04-17 05:43

你好,我想知道如何在使用 blobstoreuploadhandler 进行 HTTP POST 时,利用 WTForms 获取变量,并且希望能有国际化的本地化消息用于验证。以下是我遇到问题的代码:

class AdForm(Form):
    name = TextField(_('Name'))
    title = TextField(_('title'))
    text = TextAreaField(_('Text'),widget=TextArea())
    phonenumber = TextField(_('Phone number'))
    phonenumberhide = BooleanField(_('Display phone number on site'))
    price = TextField(_('Price'))
    password = PasswordField(_('Password'))
    email = TextField(_('Email'))

当我尝试访问通过表单提交的数据时,结果却是 None

form = AdForm(data=self.request.POST)
if form.title:
  logging.info('getting title:'+form.title.data)
  ad.title = form.title.data
  ad.save()

上面的代码没有将任何内容保存到数据存储中,这里是它来源的模板:

  <div class="labelform">
         <div class="labelform" style="clear:left;">
    <label> {% filter capitalize %}{% trans %}title{% endtrans %}{% endfilter %}:</label>
  </div>
  </div>
  </td><td>
{{ form.title }}{% if form.title.errors %}
        <ul class="errors">{% for error in form.title.errors %}<li>{{ error }}</li>{% endfor %}</ul>
    {% endif %}

你能帮我吗?在 WTForms 手册 中有关于 appengine 的内容,但我找不到一个有效的示例。

更新

我添加了验证测试,但仍然无法访问变量:

logging.info('getting requests')
if form.validate():
  if form.title:
    logging.info('getting title:'+form.title.data)
    ad.title = form.title.data
    ad.save()
    ad.put()

日志输出:

INFO 2011-11-05 23:17:24,653 main.py:1504] 正在获取请求 INFO
2011-11-05 23:17:24,653 main.py:1507] 正在获取标题:

更新 2

我移除了 WTForms 的依赖,但仍然不工作。代码 logging.info('getting data:'+ self.request.get('title', '0')) 只输出 0,尽管表单只是一个普通的 HTTP POST 表单:

 <form action="{{form_url}}" name="upload" method="post" enctype="multipart/form-data" accept-charset="utf-8">

更新 3

这个没有 WTForms 和 Jinja 的最小配置可以正常工作,所以可能是 Jinja 的问题,当这个简单的示例在 webapp2 和 Python 2.7 中工作时,我将逐行添加有问题的代码来进行故障排除:

class GuestPage(BaseHandler):
    def get(self):
        self.response.out.write("""
          <html>
            <body>
              <form action="/sign" method="post">
                <div><textarea name="content" rows="3" cols="60"></textarea></div>
                <div><input type="submit" value="Sign Guestbook"></div>
              </form>
            </body>
          </html>""")


class Guestbook(BaseHandler, I18NHandler, blobstore_handlers.BlobstoreUploadHandler):
    csrf_protect = False

    def post(self):
        self.response.out.write('<html><body>You wrote:<pre>')
        self.response.out.write(self.request.get('content'))
        self.response.out.write('</pre></body></html>')


app = webapp2.WSGIApplication([        ('/guest', GuestPage),
                                      ('/sign', Guestbook),

...

更新 4

我的基础示例在 Jinja 中工作,所以我想我可以在这个示例上继续,看看哪里出问题:

class GuestPage(BaseHandler):
    def get(self):
    self.render_jinja('form_jinja')

class Guestbook(BaseHandler, I18NHandler, blobstore_handlers.BlobstoreUploadHandler):
    csrf_protect = False

    def post(self):
        self.response.out.write('<html><body>You wrote:<pre>')
        self.response.out.write(self.request.get('content'))
        self.response.out.write('</pre></body></html>')

更新 5

我可以用这个最小示例重现错误,它无法访问 HTTP POST 变量:

class GuestPage(webapp2.RequestHandler):
    def get(self):

        self.response.out.write("""
          <html>
            <body>
              <form action=" """ +blobstore.create_upload_url('/sign')+ """ " method="post">
                <div><textarea name="content" rows="3" cols="60"></textarea></div>
                <div><input type="submit" value="Sign Guestbook"></div>
              </form>
            </body>
          </html>""")


class Guestbook(blobstore_handlers.BlobstoreUploadHandler):

    def post(self):
        self.response.out.write('<html><body>You wrote:<pre>')
        self.response.out.write(self.request.get('content'))
        self.response.out.write('</pre></body></html>')


app = webapp2.WSGIApplication([       ('/guest', GuestPage),
                                      ('/sign', Guestbook),

更新 6

从带有 blobstoreuploadhandler 的留言簿示例代码中,我可以在生产服务器上上传文件,所以我可以制作一个使用 blobstoreuploadhandler 的有效示例,我会尝试在此基础上进行构建。

更新 7

我已经让我的原始代码正常工作,除了 blob 传输。我怀疑 dev_appserver 和生产环境之间存在差异,我已经在 Google App Engine 组中发布了相关内容。我们看看后续进展。

更新 8

这是另一个常见的用法,当你添加 WTForms 时,什么都不工作:

    logging.info('getting data:'+ self.request.get('title', '0'))
    logging.info('http post data:'+ str(self.request.post))
    form = AdForm(formdata=self.request.data)
    logging.info('populated form')
    logging.info('form data:' + str(form.formdata))
    if form.validate():
      if form.title:
        logging.info('getting title:'+str( form.get('title') ) )
        ad.title = form.title.data      ad.save()       ad.put()
      if form.text:
        logging.info('getting text:' +str(form.text))
        ad.text = form.text.data
      if self.request.get('currency'):
        ad.currency = self.request.get('currency')
      if self.request.get('cg'):
        ad.category = form.cg.data
      if self.request.get('company_ad') == '1':
        ad.company_ad = True
      ad.put()
    else:
      logging.info('form did not validate')
except Exception, ex:
    logging.info('there occured exception %s', str(ex))

INFO 2011-11-09 12:11:50,868 main.py:1385] 正在获取数据:TEST INFO 2011-11-09 12:11:50,868 main.py:1409] 发生了异常 post

更新 9

最后,表单填充了数据,只是没有通过验证。感谢 Sean 提供的信息让我更进一步。现在我可以填充表单对象而没有异常,但在尝试验证时却出现了异常:

logging.info('getting data:'+ self.request.get('title', '0'))
form = AForm(self.request.POST)
logging.info('populated form')
if form.validate():
  logging.info('validated form')

上面的代码正在记录输出:

INFO     2011-11-11 08:03:59,913 main.py:1387] getting data:TEST
INFO     2011-11-11 08:03:59,914 main.py:1390] populated form
INFO     2011-11-11 08:03:59,914 main.py:1412] there occured exception 'builtin_function_or_method' object is not iterable

这个异常是什么意思?

我的表单类是:

class AForm(Form):
    name = TextField(_('Name'))
    title = TextField(_('title'))
    text = TextAreaField(_('Text'),widget=TextArea())
    phonenumber = TextField(_('Phone number'))
    phonenumberhide = BooleanField(_('Display phone number on site'))
    price = TextField(_('Price'))
    password = PasswordField(_('Password'))
    email = TextField(_('Email'))  
    category  = SelectField(choices=categories.keys)

2 个回答

1

丹尼尔,其实你需要传给表单的不是data=self.request.POST,而是formdata。你可以查看这个链接了解更多:http://wtforms.simplecodes.com/docs/dev/forms.html#the-form-class

希望这对那些像我一样匆忙浏览文档的人有帮助。

1

我对WTForm不太了解,但我猜它和Django的表单类似,你需要在访问数据之前先调用验证函数。在这种情况下,就是form.validate()

form = AdForm(formdata=self.request.POST)
if form.validate():
    ad.title = form.title.data

撰写回答