# ! /usr/bin/env python
# -*- coding: utf-8 -*-
# image_slide.py
""" Python 2.7.3
Cherrypy 3.2.2
"""
当HTML表单提交给Python函数时,值将在一个字典中发送。对于HTML表单中的某些子元素,我想在该表单字典中POST一个额外的嵌套字典。问题是,如果有HTML标签或类似的东西,Python会将其解释为新字典的开头。到目前为止,我尝试命名<td>
或隐身<fieldset>
,但当然不是那么简单。并且嵌套表单也是不可能的。
我所拥有的是一个表单,其中包含一些文本输入和一个包含相关项目选择的表。
_____ the entire form __________________________________________________________
| |
| beverage: coffee |
| time of day: morning |
| temperature: hot |
| color: brown |
| taste: full-bodied |
| |
| Ingredients: |
| ________________________________________________________________________ |
| | | | | | |
| | <IMAGE_1> | <IMAGE_2> | <IMAGE_3> | <IMAG| |
| | | | | | |
| | filename: coffee | filename: sugar | filename: milk | filename:| |
| | x select item | x select item | x select item | x select | |
| |___________________|___________________|___________________|__________| |
| |_____________________________<scrollbar>______________________________| |
| |
| < OK > |
|______________________________________________________________________________|
以下是三个简单的伪代码片段来解释这个要点。
一个表单条目的内容:
beverages = {
'coffee': {
'beverage': 'coffee',
'time of day': 'morning',
'temperature': 'hot',
'color': 'brown',
'taste': 'full-bodied',
}
}
ingredients = {
'coffee': [
'coffee',
'sugar',
'milk',
'cinnamon',
],
}
表单的顶部:
yield(u'''
<form action="..." method="POST">
<table>
''')
for key, value in beverages['coffee'].items():
yield(u'''
<tr>
<td> {key}: </td>
<td> <input type="text" name="{key}" value="{value}">< /td>
</tr>
'''.format(locals(),)
表格的下半部分:
""" This hole bottom part already shall be in a dictionary named 'ingredients'.
For each loop pass, I'd like a sub-dictionary, named by its loop pass.
I used the fictional tag <SPECIAL_SUB_DICT>, to open a new dictionary.
"""
yield(u'''
</table>
<SPECIAL_SUB_DICT name="ingredients">
<table style="overflow-x: scroll">
<tr>
''')
for index, name in enumerate(ingredients['coffee']):
yield(u'''
<td>
<SPECIAL_SUB_DICT name="{index}">
<img src="...">
<input type="text" name="filename" value="{name}">
<input type="check" name="chosen_one" value="{index}"> select item
</SPECIAL_SUB_DICT>
</td>
'''.format(locals(),)
yield(u'''
</tr>
</table>
</SPECIAL_SUB_DICT>
<input type="submit" name="submit" value="OK">
</form>
''')
问题是,如果没有某种<SPECIAL_SUB_DICT>
标签,我就不能轻易地重命名单一成分。例如,如果我想将文件名从'milk'更改为'hole cream milk'。我现在的方法是,将当前循环传递添加到输入名称,如下所示:
'<input type="text" name="filename_{index}" value="{name}"> '.format(locals(),)
然后,在接收函数中,我可以检查哪个键以'filename_'开头并更新所有键:
for key, values in kwargs:
if key startswith('filename_'):
ingredients['coffee'][key[9:]] = value
如果我可以迭代kwargs['ingredients']
:
for key, values in kwargs['ingredients'].items():
ingredients['coffee'][key] = value[filename]
我问,因为<SPECIAL_SUB_DICT>
标签比使用Python的BeautifulSoup解析表更接近我当前的解决方案。当然,我想知道它。毕竟,有了BeautifulSoup,我现在可能已经完成了。
编辑1:
这与Web应用程序框架CherryPy一起运行 也许有办法可以处理这样的请求 虽然我没想到,它会提供一些不合标准的东西。
编辑2:
鉴于表单字典在带有问号的URL中开始,我不认为子字典是可能的,因为我不知道任何字典结束字符。我能想到的最接近的事情是使用名为'index'的隐藏输入,并使用名为'filename'的文本输入zip()。不幸的是,对于PHP来说,This answer让我朝着正确的方向前进。
'<input type="hidden" name="index" value="{index}"> '.format(locals(),)
'<input type="text" name="filename" value="{name}"> '.format(locals(),)
for key, values in zip(kwargs['index'], kwargs['filename']):
ingredients['coffee'][key] = value
然而,这不适用于我计划添加到每种成分的删除按钮。由于只有提交输入可以携带索引,并且其值用于显示按钮的unicode符号,我再次必须将索引附加到名称。
然后,我唯一能想到的是每种成分的形式和公式的顶部,而不是一种大的形式。虽然我不知道这对表现是否有好处,但如果成分列表变得太长了。
作为视觉技巧,需要考虑背景图像,以替换值,然后透明地根据其名称使用。 This answer及其相应的问题有助于它的运作。
但这不能解决我的问题
我仍然缺少所有输入的解决方案,
喜欢多种形式,更优雅。
答案 0 :(得分:0)
好的,我也想知道这是如何完成的,所以你开始吧。这仅适用于单级字典。如果你想让这个递归,我会把它留给你。
这个问题:<input name="foo[bar]">
是 foo[bar]
是变量名,括号被转换为 URL 安全实体:
[DEBUG] BODY_TEXT: foo%5Bbar%5D=input_value
CherryPy 允许您通过在 cherrypy.request.body.processors
中定义可调用对象来定义 custom body processor,cherrypy.tools.json_in()
是一个键与内容类型匹配的字典。这就是 application/json
工具的工作原理,即在请求的内容类型为 {'foo': 'bar'}
时将主体处理器替换为解析 JSON 的函数。
您需要的最后一部分是如何将解析后的字典(即 import re
import cherrypy
import logging
import urllib
class ImprovedFormInput(cherrypy.Tool):
def __init__(self):
logging.debug('ImprovedFormInput.__init__()')
cherrypy.Tool.__init__(self, 'before_request_body', self.handle_post, priority=50)
def handle_post(self):
logging.debug('ImprovedFormInput.handle_post()')
request = cherrypy.serving.request
def impfin_processor(entity):
raw_body = entity.fp.read()
body_text = raw_body.decode()
logging.debug('BODY_TEXT: %s', body_text)
parsed = urllib.parse.parse_qs(body_text)
logging.debug('PARSED: %s', parsed.keys())
form_inputs = {}
r = re.compile(r'^(\w+)\[(.+)\]$') # This pattern could be better
for key in parsed.keys():
m = r.match(key)
if m is None:
continue
groups = m.groups()
pkey = groups[0]
logging.debug('PKEY: %s', pkey)
ckey = groups[1]
logging.debug('CKEY: %s', ckey)
if pkey not in form_inputs:
form_inputs[pkey] = {}
form_inputs[pkey][ckey] = parsed[key]
logging.debug('FINPUTS: %s', form_inputs)
# https://github.com/cherrypy/cherrypy/blob/main/cherrypy/_cpreqbody.py#L177
for key, value in form_inputs.items():
if key in entity.params:
if not isinstance(entity.params[key], list):
entity.params[key] = [entity.params[key]]
entity.params[key].append(value)
else:
entity.params[key] = value
request.body.processors['application/x-www-form-urlencoded'] = impfin_processor
注入处理程序方法的参数中,以便像常规 POST 输入变量一样使用。我直接从默认表单处理器中获取它:{{3 }}
所以这是工具。您需要在您的配置中启用它,并将其加载到您的服务器脚本中,但它将采用一组 dict 形状的表单输入将 dict 传递给您的处理程序。它使用正则表达式来实现这一点。
{{1}}