お世話になっております。
DjangoにてPOSTした内容からDictに変換する方法をさがしているのですが、いい方法がありましたらご教示頂けますと幸いです。
実現したい内容は、
下記のようなフォームからPOSTを行い、
<tr>
<td>
<input name="key" value="名称1">
</td>
<td>
<input name="Status1" value="値1-1">
<td>
<input name="Status2" value="値1-2">
</td>
</tr>
<tr>
<td>
<input name="key" value="名称2">
</td>
<td>
<input name="Status1" value="値2-1">
<td>
<input name="Status2" value="値2-2">
</td>
</tr>
<tr>
<td>
<input name="key" value="名称3">
</td>
<td>
<input name="Status1" value="値3-1">
<td>
<input name="Status2" value="値3-2">
</td>
</tr>
~ jqueryで 行は増やせるようにしています ~
POSTされた内容を下記のようなdictで保存を行いたい感じです。
field = {
'名称1' : {'status1' : '値1-1', 'status1' : '値1-2', },
'名称2' : {'status1' : '値2-1', 'status1' : '値2-2', },
'名称3' : {'status1' : '値3-1', 'status1' : '値3-2', }
}
一応、現時点で下記のようにコードは書けて、実現はできております。、
field = {}
parameters = request.POST
keys = parameters.getlist('key')
value1 = parameters.getlist('value1')
vakue2 = parameters.getlist('value2')
for i in range(len(keys)):
field[keys[i]] = {
'value1' : value1[i],
'value2' : value2[i],
}
が、このコードだと値がズレて保存されてしまう可能性があり、何かベストな記述が出来ないか模索中です。
何かヒント等を頂けましたらとても助かります。
DjangoでPOSTされたフォームの内容を辞書に変換する際、各行の複数の値をキーに対応させるためには、フォームの構造を少し変更して、各行ごとに一意の識別子を持たせることが効果的です。
jQueryを使用して行を動的に増やしているとのことですので、各行にインデックスや一意のIDを付与し、そのIDをキーとしてフォームのname属性に組み込むことで、サーバー側での処理を容易にします。
例えば、以下のようにフォームを修正します。
<tr>
<td>
<input name="items[0][key]" value="名称1">
</td>
<td>
<input name="items[0][Status1]" value="値1-1">
</td>
<td>
<input name="items[0][Status2]" value="値1-2">
</td>
</tr>
<tr>
<td>
<input name="items[1][key]" value="名称2">
</td>
<td>
<input name="items[1][Status1]" value="値2-1">
</td>
<td>
<input name="items[1][Status2]" value="値2-2">
</td>
</tr>
<tr>
<td>
<input name="items[2][key]" value="名称3">
</td>
<td>
<input name="items[2][Status1]" value="値3-1">
</td>
<td>
<input name="items[2][Status2]" value="値3-2">
</td>
</tr>
そして、Django側でこの構造に合わせてデータを処理します。以下はその一例です:
from django.http import HttpRequest
def your_view_function(request: HttpRequest):
# まず、itemsというキーでPOSTされたデータを取得
items = request.POST.getlist('items')
field = {}
for item in items:
# 各アイテム(行)のデータを取得
key = item.get('key')
if key: # キーが存在する場合のみ処理
# 辞書に格納
field[key] = {
'status1': item.get('Status1', ''),
'status2': item.get('Status2', '')
}
return field
ただし、このコードは request.POST.getlist('items')
で期待通りのデータを取得できる前提で書かれていますが、実際には request.POST
からこのようなネストされたデータ構造を直接取得することはできません。
request.POST
は QueryDict
オブジェクトで、このようなネストされたデータ構造を扱うためには、カスタムのパース処理を実装する必要があります。
正確には、以下のようにPOSTデータの処理を行います:
def your_view_function(request):
field = {}
for key in request.POST.keys():
if key.startswith('items['):
# フィールド名からインデックスと実際のキーを抽出
_, index, field_name = key.strip(']').split('[')
index = int(index) # インデックスを整数に変換
if 'key' in field_name:
# キーの場合は、新しいエントリを作成
real_key = request.POST[key]
field.setdefault(real_key, {})
else:
# Status1, Status2の場合は、既存のエントリを更新
real_key = request.POST[f'items[{index}][key]']
field[real_key][field_name.lower()] = request.POST[key]
return field
このように、items[インデックス][フィールド名]
形式のフィールド名を解析して、必要なデータ構造を構築します。
ただし、この例では動的に増えるフォームフィールドに対応するための一般的なアプローチを示していますが、実際のプロジェクトの詳細に応じて適宜調整が必要になります。
試してみてください。
はるさん
ありがとうございます。
ご教示いただきました方法(フィールド名をパースしてからの検索)にてうまくいきました!
dictにkeyが存在しない場合のエラーを想定 + 重複する記述を省くために下記のように変更して書いてみました。
# inputのnameは row[(int)][(str)]にて設定
# key.strip(']')で吐き出す結果が'row[(int)][(bill)'となってしまったので、正規表現にて抽出
fields = {}
parameters = request.POST
for key in parameters.keys():
if key.startswith('row['):
index, field = re.findall('\[(\d+)\]\[(.+)\]', key)[0]
index = int(index)
if 'key' in field:
continue
real_key = parameters[f'row[{index}][key]']
if not real_key in fields :
fields.setdefault(real_key, {})
fields[real_key][field.lower()] = int(parameters[key])
何度も助けていただきありがとうございます m(_ _)m