2
# ! /usr/bin/env python
# -*- coding: utf-8 -*-
# image_slide.py

""" Python        2.7.3
    Cherrypy      3.2.2
"""

当 HTML 表单提交给 Python 函数时,值会在一个字典中发送。对于 HTML 表单中的某些子元素,我想在该表单字典中发布一个额外的嵌套字典。问题是,如果有 HTML 标记或类似的东西,Python 会将其解释为打开新字典。到目前为止,我尝试将<td>or 命名为 invisible <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,这个答案让我朝着正确的方向前进。

'<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 符号,所以我再次必须将索引附加到名称中。

然后,我唯一能想到的就是每种成分的表格和配方的顶部,而不是所有东西的一个大表格。虽然我不知道这是否对性能有好处,但如果成分列表变得太长。

作为一个视觉技巧,我想到了一个背景图像,以替换该值,然后可以根据其名称透明地使用该值。这个答案及其相应的问题有助于让它发挥作用。

但这一切都不能回答我的问题。
我仍然缺少适用于所有输入的一种解决方案,
比如多种形式,只是更优雅。

4

1 回答 1

0

好的,我也想知道这是如何完成的,所以给你。这仅适用于单级字典。如果你想让这个递归,我会把它留给你。

问题在于:<input name="foo[bar]">foo[bar]是变量名,括号被转换为 URL 安全实体:

[DEBUG] BODY_TEXT: foo%5Bbar%5D=input_value

CherryPy 允许您通过定义可调用 in来定义自定义正文处理器cherrypy.request.body.processors,该可调用 in是其键与内容类型匹配的字典。这就是该cherrypy.tools.json_in()工具的工作方式,通过在请求的内容类型为application/json.

您需要的最后一部分是如何注入解析的字典(即{'foo': 'bar'}注入处理程序方法的参数中,就像常规 POST 输入变量一样使用。我直接从默认表单处理器中获取它:https ://github.com/cherrypy/cherrypy /blob/main/cherrypy/_cpreqbody.py#L177

所以这里是工具。您需要在您的配置中启用它,并将其加载到您的服务器脚本中,但它将需要一组 dict 形的表单输入将 dict 传递给您的处理程序。它使用正则表达式执行此操作。

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
于 2021-03-24T23:49:09.680 回答