2016-02-08 5 views
2

У меня есть приложение фляги, которое получает запрос от редактора DataTables. После получения на сервере, request.form выглядит как (например)Как декодировать dataTables Редактор формы в колбе питона?

ImmutableMultiDict([('data[59282][gender]', u'M'), ('data[59282][hometown]', u''), 
('data[59282][disposition]', u''), ('data[59282][id]', u'59282'), 
('data[59282][resultname]', u'Joe Doe'), ('data[59282][confirm]', 'true'), 
('data[59282][age]', u'27'), ('data[59282][place]', u'3'), ('action', u'remove'), 
('data[59282][runnerid]', u''), ('data[59282][time]', u'29:49'), 
('data[59282][club]', u'')]) 

Я имею в виду, чтобы использовать что-то подобное этому действительно уродливый код, чтобы расшифровать его. Есть ли способ лучше?

from collections import defaultdict 

# request.form comes in multidict [('data[id][field]',value), ...] 
# so we need to exec this string to turn into python data structure 
data = defaultdict(lambda: {}) # default is empty dict 

# need to define text for each field to be received in data[id][field] 
age = 'age' 
club = 'club' 
confirm = 'confirm' 
disposition = 'disposition' 
gender = 'gender' 
hometown = 'hometown' 
id = 'id' 
place = 'place' 
resultname = 'resultname' 
runnerid = 'runnerid' 
time = 'time' 

# fill in data[id][field] = value 
for formkey in request.form.keys(): 
    exec '{} = {}'.format(d,repr(request.form[formkey])) 

ответ

0

я решил по пути, который является более безопасным, чем с помощью Exec:

from collections import defaultdict 

def get_request_data(form): 
    ''' 
    return dict list with data from request.form 

    :param form: MultiDict from `request.form` 
    :rtype: {id1: {field1:val1, ...}, ...} [fieldn and valn are strings] 
    ''' 

    # request.form comes in multidict [('data[id][field]',value), ...] 

    # fill in id field automatically 
    data = defaultdict(lambda: {}) 

    # fill in data[id][field] = value 
    for formkey in form.keys(): 
     if formkey == 'action': continue 
     datapart,idpart,fieldpart = formkey.split('[') 
     if datapart != 'data': raise ParameterError, "invalid input in request: {}".format(formkey) 

     idvalue = int(idpart[0:-1]) 
     fieldname = fieldpart[0:-1] 

     data[idvalue][fieldname] = form[formkey] 

    # return decoded result 
    return data 
0

Этот вопрос имеет принятый ответ и немного старый, но так как DataTable модуль кажется, является довольно популярным среди JQuery сообщества Тем не менее, я считаю, что этот подход может быть полезен для кого-то другого. Я просто написал простую функцию синтаксического анализа, основанную на регулярном выражении, и dpath module, хотя он выглядит не совсем надежным модулем. Фрагмент может быть не очень простым из-за фрагмента, связанного с исключениями, но это был единственный способ предотвратить dpath от попыток разрешить строки в виде целочисленных индексов, которые я нашел.

import re, dpath.util 

rxsKey = r'(?P<key>[^\W\[\]]+)' 
rxsEntry = r'(?P<primaryKey>[^\W]+)(?P<secondaryKeys>(\[' \ 
     + rxsKey \ 
     + r'\])*)\W*' 

rxKey = re.compile(rxsKey) 
rxEntry = re.compile(rxsEntry) 

def form2dict(frmDct): 
    res = {} 
    for k, v in frmDct.iteritems(): 
     m = rxEntry.match(k) 
     if not m: continue 
     mdct = m.groupdict() 
     if not 'secondaryKeys' in mdct.keys(): 
      res[mdct['primaryKey']] = v 
     else: 
      fullPath = [mdct['primaryKey']] 
      for sk in re.finditer(rxKey, mdct['secondaryKeys']): 
       k = sk.groupdict()['key'] 
       try: 
        dpath.util.get(res, fullPath) 
       except KeyError: 
        dpath.util.new(res, fullPath, [] if k.isdigit() else {}) 
       fullPath.append(int(k) if k.isdigit() else k) 
      dpath.util.new(res, fullPath, v) 
    return res 

Практическое использование основано на нативного метода Колбу request.form.to_dict():

# ... somewhere in a view code 
    pars = form2dict(request.form.to_dict()) 

Выходная структура включает в себя как, словарь и списки, как можно было бы ожидать. Например:

# A little test: 
rs = jQDT_form2dict({ 
     'columns[2][search][regex]' : False, 
     'columns[2][search][value]' : None, 
     'columns[2][search][regex]' : False, 
    }) 

генерирует:

{ 
    "columns": [ 
     null, 
     null, 
     { 
      "search": { 
       "regex": false, 
       "value": null 
      } 
     } 
    ] 
} 

Обновления: обрабатывать списки как словари (в более эффективном способе) можно упростить этот фрагмент с следующим блоком на else частях if пункта:

# ... 
    else: 
     fullPathStr = mdct['primaryKey'] 
     for sk in re.finditer(rxKey, mdct['secondaryKeys']): 
      fullPathStr += '/' + sk.groupdict()['key'] 
     dpath.util.new(res, fullPathStr, v) 
+0

Мне любопытно, как это будет работать с моим оригинальным примером, где мой идентификатор 59282? Возможно, чистый диктовский подход лучше для редкого «списка»? –

+0

О, это хороший момент. Обновлен мой ответ с альтернативным предложением 'else'. – Crank

Смежные вопросы