【问题标题】:Converting MultiDict to proper JSON将 MultiDict 转换为正确的 JSON
【发布时间】:2017-04-01 03:37:16
【问题描述】:

我使用 Flask (python) 发布表单时收到的 MultiDict (ImmutableMultiDict) 是

ImmutableMultiDict([
    ('disabled', 'False'), 
    ('disabled', 'False'), 
    ('debet', '11'), 
    ('debet', '21'), 
    ('date', '2016-11-17'), 
    ('kredit', '12'), 
    ('kredit', '22'), 
    ('record', '1901'), 
    ('record', '1902'), 
    ('description', 'Sales of inventory')
])

我发布的表单看起来像

<form method="POST" action="/post">
    <input name="description" value="Sales of inventory" />
    <input name="date" value="2016-11-17" />
    <div class="group">
        <input name="record" value="1901" />
        <input name="debet" value="11" />
        <input name="kredit" value="12" />
        <input name="disabled" value="False" />
    </div>
    <div class="group">
        <input name="record" value="1902" />
        <input name="debet" value="21" />
        <input name="kredit" value="22" />
        <input name="disabled" value="False" />
    </div>
</form>

我想将此表单(不包括描述和日期)输入转换为类似的 JSON 格式

data = [
    {
        "record": 1901,
        "debet": 11,
        "kredit": 12,
        "disabled": False
    },
    {
        "record": 1902,
        "debet": 21,
        "kredit": 22,
        "disabled": False
    }
]

有什么好办法吗?我已经尝试了很多东西,但我无法正确弄清楚。

【问题讨论】:

  • 不,我看不到这样做的好方法。您收到的数据不保留已发布表单的结构。您可以假设每个键中的第一个键与其他键中的第一个键一起出现,第二个键与第二个键一起出现,但我不知道这是否在任何地方都能保证。
  • 如果您在表单中使用input name="record[1]"input name="record[2]" 会怎样?这会改变您收到的ImmutableDict 吗?
  • Python 和 Flask 不接受 json 格式的 post 消息。回复是ImmutableMultiDict([('record[2]', '1902'), ('disabled[2]', 'False'), ('record[1]', '1901'), ('date', '2016-11-17'), ('debet[1]', '11'), ('kredit[2]', '22'), ('kredit[1]', '12'), ('debet[2]', '21'), ('description', 'Domännamn'), ('disabled[1]', 'False')])
  • 为输入设置正确的字段名称后,您可以自己解析ImmutableDict

标签: python json dictionary flask


【解决方案1】:

如果您绝对无法更改数据的发送方式,并且您确定数据始终以与表单相同的顺序发送(请确保这一点,否则无法分辨哪些值一起去),那么你可以这样做:

fields = ['record', 'debet', 'kredit', 'disabled']

num_values = len(form_data.getlist(fields[0]))

data = []

for i in range(num_values):
    data.append({field: form_data.getlist(field)[i] for field in fields})

但是,我不建议这样做。归根结底,您以某种方式动态生成新输入,因为您似乎有动态数量的字段,所以为什么不直接将名称更改为 record1、record2 等正在做这个吗?

【讨论】:

    【解决方案2】:

    您可以使用 jquery 来执行此操作。它只是意味着您使用 ajax 发布,而不是从表单发布。在下面的代码中,组中每个子项的名称和值被收集到一个名为“组”的对象中。一旦为一个组收集了所有名称和值,“组”对象就会被推送到一个名为“数据”的数组中。这个对象数组是 JSON.stringified 并通过 $.ajax() 发布到烧瓶。

    以下是html/javascript端:

    <!--index.html-->
    <html>
    <head>
        <script
            src="https://code.jquery.com/jquery-3.1.1.js"
            integrity="sha256-16cdPddA6VdVInumRGo6IbivbERE8p7CQR3HzTBuELA="
            crossorigin="anonymous">
        </script>
    </head>
    <body>
        <form>
            <input name="description" value="Sales of inventory" />
            <input name="date" value="2016-11-17" />
            <div class="group">
                <input name="record" value="1901" />
                <input name="debet" value="11" />
                <input name="kredit" value="12" />
                <input name="disabled" value="False" />
            </div>
            <div class="group">
                <input name="record" value="1902" />
                <input name="debet" value="21" />
                <input name="kredit" value="22" />
                <input name="disabled" value="False" />
            </div>
        </form>
        <button id='submitBtn'>Submit</button>
        <script>
            $(function() {
                $('#submitBtn').on('click', function() {
                    var data = [];
                    $('.group').each(function(group_idx) {
                        var group_this = $(this);
                        var group = {};
                        group_this.children('input').each(function(input_idx) {
                            var input_this = $(this);
                            group[input_this.attr('name')] = input_this.val();
                        });
                        data.push(group);
                    });
                    $.ajax({
                        type: 'POST',
                        url: '/post',
                        data: JSON.stringify(data),
                        contentType: 'application/json;charset=UTF-8',
                    }).done(function(resp) {
                        console.log('done');
                    }).fail(function(resp) {
                        console.log('failed');
                    });
                });
            });
        </script>
    </body>
    

    然后在flask中你可以使用request.json来检索数据。

    from pprint import pprint 
    from flask import Flask, request, render_template, redirect
    
    app = Flask(__name__)
    
    @app.route('/', methods=['GET'])
    def index():
        return render_template('index.html')
    
    @app.route('/post', methods=['POST'])
    def post():
        data = request.json
        pprint(data)
        return redirect('/')
    
    if __name__ == '__main__':
        app.run(debug=True)
    

    【讨论】:

    • 如果您想包含 javascript,这是一个很好的解决方案。无论您是否启用了 javascript,我都希望表单能够正常工作,因此我相信我的解决方案会更好。
    【解决方案3】:

    在 kiran.koduru 的帮助下,我解决了我的具体问题

    def jsonify_data(N, data=[]):
        totalRows = int((len(N) - 2) / 4)
        row = {}
        for i in range(totalRows):
            for (key, value) in N.items():
                if key == 'record[' + str(i) + ']':
                    row['record'] = value
                if key == 'debet[' + str(i) + ']':
                    row['debet'] = value
                if key == 'kredit[' + str(i) + ']':
                    row['kredit'] = value
                if key == 'disabled[' + str(i) + ']':
                    row['disabled'] = value
            if(row):
                data.append(row)
                row = {}
        return data
    

    然后我只是将收到的表单用作

    jsonify_data(request.form)
    

    我已经定义了data=[],以便我以后可以使用它,并将数据库中已有的内容组合为

    jsonify_data(request.form, json_data_from_database)
    

    编辑: 我使用的数据库是带有 SQLAlchemy 的 PostgreSQL,我意识到我无法更新数据库中的值。我添加了一行复制之前的数据,不要马上用它来解决问题。

    def jsonify_data(N, P):
        // ADDED THIS
        data = P[:]
        totalRows = int((len(N) - 2) / 4)
        row = {}
        for i in range(totalRows):
            for (key, value) in N.items():
                if key == 'record[' + str(i) + ']':
                    row['record'] = value
                if key == 'debet[' + str(i) + ']':
                    row['debet'] = value
                if key == 'kredit[' + str(i) + ']':
                    row['kredit'] = value
                if key == 'disabled[' + str(i) + ']':
                    row['disabled'] = value
            if(row):
                data.append(row)
                row = {}
        return data
    

    【讨论】:

    • 非常好 :) 很高兴我能帮上忙。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-21
    • 2014-11-05
    • 2018-05-09
    • 1970-01-01
    • 2021-07-27
    相关资源
    最近更新 更多