Розничная форма деформации (с использованием атрибута формы) - обработка даты ненадежна

Краткое резюме: как обеспечить правильный порядок значений в request.POST?

Я использую таблицу HTML (дополненную с помощью DataTables для скрытия столбцов и т. д., с единственным эффектом, заключающимся в том, что скрытые столбцы не включаются в вызов «отправить») и отображаю одну форму деформации для каждой строки.

Поскольку деформация не поддерживает раздельные формы напрямую с помощью атрибута формы, я вручную вставляю form=my_desired_unique_id во все соответствующие элементы. Это отлично работает для простых элементов, таких как <input> и <textarea>, значения отображаются в request.POST.items() и проходят проверку.

Однако для средства выбора даты деформации все немного сложнее. form['datecolumn'].serialize будет генерировать что-то вроде этого: -

<input type="hidden" name="__start__" value="datecolumn:mapping"/>
<input type="date"
       name="date"
       value="2017-01-01"
       id="deformField6" class="  form-control hasDatepicker"/>
<input type="hidden" name="__end__" value="datecolumn:mapping"/>
<script type="text/javascript">
 deform.addCallback(
  'deformField6',
   function deform_cb(oid) {
     if (!Modernizr.inputtypes['date'] ||"date" != "date" || window.forceDateTimePolyfill){
       $('#' + oid).pickadate({"format": "yyyy-mm-dd", "selectMonths": true, "selectYears": true, "formatSubmit": "yyyy-mm-dd"});
     }
   }
 );
</script>

Там есть 3 входа (и четвертый скрытый добавляется в отображаемый HTML с именем «date_submit»). Значение видимого ввода не изменяется, когда пользователь выбирает новую дату, но меняется новое скрытое значение. При отправке это значение каким-то образом передается на основной ввод «дата» (некоторые js, с которыми у меня нет дескриптора).

Результирующий request.POST.items() содержит эти три элемента из ввода даты:

  1. ('__start__', 'datecolumn:mapping')
  2. ('date', '2017-02-24') (это вновь выбранная дата)
  3. ('__end__', 'datecolumn:mapping')

Моя проблема в том, что порядок этих значений ненадежен. На одной и той же странице и в форме многократное нажатие кнопки «Отправить» приведет к различному порядку значений в request.POST.items() (все значения, а не только связанные с датой). Если результирующий порядок такой, как указано выше, все работает нормально, но если порядок другой (скажем, конец перед началом или дата после или до обоих), то я либо получаю ValueError, либо сбой проверки.

Возможно, я мог бы сначала перебрать request.POST.items() и обеспечить правильное расположение, но мне нужны два средства выбора даты в этой форме, и у меня нет возможности узнать, какое поле date принадлежит какой паре маркеров __start__ и __end__.

Есть ли способ контролировать порядок элементов в POST до того, как он будет отправлен в мой код просмотра?


person Ng Oon-Ee    schedule 23.02.2017    source источник


Ответы (1)


Придуманный мной хак (приму любые лучшие ответы, чем этот!) состоит из двух частей.

  1. Отметьте каждый элемент даты (я называю все свои элементы даты как *_date) уникальным в моем шаблоне.

  2. Используйте шаблон для повторного создания соответствующих элементов POST.

В частности, для первого шага я создаю сериализованный виджет, используя эту функцию: -

def serialize_with_formid(form, elem_name, formid):
    retval = form[elem_name].serialize()
    retval = retval.replace('<input type=', '<input form={} type='.format(formid))
    retval = retval.replace('<textarea', '<textarea form={}'.format(formid))
    if elem_name.endswith('date'):  # 'Mark' datepick elements appropriately
        retval = retval.replace('name="date"', 'name="{}"'.format(elem_name))
    return retval

form — это созданный экземпляр формы, elem_name заканчивается «датой» для элементов средства выбора даты, а formid уникален для каждой формы на странице (которых на моей странице много). Строки 2 и 3 вставляют formid, где это уместно, а if отмечает элементы средства выбора даты.

На шаге 2 я сначала удаляю все элементы __start__ и __end__ из request.POST, затем нахожу элементы в request.POST, которые заканчиваются на date, и использую их для добавления (в правильном порядке) элементов в request.POST.

def fix_broken_POST(request):
    '''
    For some reason I'm getting POST elements out of order with retail rendered
    form-attribute reliant forms. This reorders the crucial elements (date-related)
    so that deform can then do validation etc.
    '''
    while True:
        try:  # Assumes same number of both
            request.POST.pop('__start__')
            request.POST.pop('__end__')
        except KeyError as e:
            break
    list_of_date_keys = [i for i in request.POST.keys() if i.endswith('date')]
    list_of_tuples = []
    for key in list_of_date_keys:
        value = request.POST.pop(key)
        list_of_tuples.append(('__start__', '{}:mapping'.format(key)))
        list_of_tuples.append(('date', value))
        list_of_tuples.append(('__end__', '{}:mapping'.format(key)))
    request.POST.extend(list_of_tuples)

Опять же, это, очевидно, хак/обходной путь, поэтому было бы полезно что-то более... элегантное.

person Ng Oon-Ee    schedule 24.02.2017