Правильный подход для последовательных, зависимых форм WTF [дубликат]

Оператор запятой объединяет два выражения с обеих сторон в один, оценивая их как в порядке слева направо. Значение правой части возвращается как значение всего выражения. (expr1, expr2) походит на { expr1; expr2; }, но вы можете использовать результат expr2 в вызове функции или присваивании.

Часто в циклах for можно инициализировать или поддерживать несколько переменных:

for (low = 0, high = MAXSIZE; low < high; low = newlow, high = newhigh)
{
    /* do something with low and high and put new values
       in newlow and newhigh */
}

Кроме этого, я использовал его только «в гневе» в одном другом случае, когда вы завершаете две операции, которые всегда должны совпадать в макросе. У нас был код, который копировал различные двоичные значения в байтовый буфер для отправки по сети, и указатель поддерживался там, где мы вставали:

unsigned char outbuff[BUFFSIZE];
unsigned char *ptr = outbuff;

*ptr++ = first_byte_value;
*ptr++ = second_byte_value;

send_buff(outbuff, (int)(ptr - outbuff));

Где значения были short s или int s мы сделали это:

*((short *)ptr)++ = short_value;
*((int *)ptr)++ = int_value;

Позже мы читаем, что это не было действительно действительным C, потому что (short *)ptr больше не является l-значением и не может быть увеличено, хотя наш компилятор на время не против. Чтобы исправить это, мы разделили это выражение на два:

*(short *)ptr = short_value;
ptr += sizeof(short);

. Однако этот подход основывался на том, что все разработчики помнят, что оба оператора все время заставляют. Нам нужна функция, в которой вы могли бы передать указатель на выход, значение и тип значения. Это C, а не C ++ с шаблонами, мы не могли бы иметь функцию произвольного типа, поэтому мы остановились на макросе:

#define ASSIGN_INCR(p, val, type)  ((*((type) *)(p) = (val)), (p) += sizeof(type))

Используя оператор запятой, мы смогли использовать это в выражения или как заявления, которые мы хотели:

if (need_to_output_short)
    ASSIGN_INCR(ptr, short_value, short);

latest_pos = ASSIGN_INCR(ptr, int_value, int);

send_buff(outbuff, (int)(ASSIGN_INCR(ptr, last_value, int) - outbuff));

Я не предлагаю, чтобы какой-либо из этих примеров был хорошим стилем! Действительно, я, кажется, помню, что Code Complete Стив МакКоннелл предупреждал даже использовать запятые в цикле for: для удобочитаемости и ремонтопригодности цикл должен управляться только одной переменной, а выражения в for сама строка должна содержать только код управления контуром, а не другие дополнительные биты инициализации или обслуживания цикла.

4
задан user455318 19 October 2014 в 23:29
поделиться

2 ответа

Я лично предложил бы использовать объект сеанса для передачи данных из одной формы в другую. Если у вас есть небольшой объем данных, вы можете уйти, просто используя реализацию куки-файлов, которые есть в колбе. В противном случае, вы можете переопределить объект сеансов по умолчанию для хранения сеансов сервера данных с помощью Redis. Это позволяет использовать объекты сеанса, не платя цену хранения большого количества данных в файлах cookie. Это означает, что вы можете сделать что-то вроде

@app.route('/form/step1', methods=['GET', 'POST'])
def form_step1():
    form1 = form_step_1(request.POST)
    user_id = current_user.user_id # If you're using flask-login
    ...validate()...
        # dictionary that holds form1, form2, etch
        form_data = {"form1": form1, "form2": None, "Form3"=None} 
        flask.session[user_id] = form_data
        redirct_to(url_for("form_step2"))
    return render_template('register.html', {'form':form1})  

@app.route('/form/step2', methods=['GET', 'POST'])
def form_step2():
    form1 = session[user_id][form1]
    # A simpler way than passing the whole form is just the data 
    # you want but for this answer I'm just specifying the whole form.
    form = form_step_2(form1)
    user_id = current_user.user_id # If you're using flask-login 
    ...validate()...
        # dictionary that holds form1, form2, etch
        flask.session[user_id]["form2"] = form2
        redirct_to(url_for("form_step3"))
    return render_template('register.html', form=form)
3
ответ дан AlexLordThorsen 22 August 2018 в 09:08
поделиться
  • 1
    Другой способ, возможно, я могу использовать flask-redis для временного хранения данных каждого шага. Редис был создан для этого. – user455318 22 October 2014 в 18:10
  • 2
    Я абсолютно согласен. Мне лично нравится использовать объект сеанса, потому что мои приложения уже извлекают данные из сеансов, и он выглядит таким же образом. Но использование фляги-redis - вполне правильный выбор. – AlexLordThorsen 22 October 2014 в 22:06
  • 3
    Я получаю ошибки с тем, где мои формы не являются JSON-сериализуемыми & quot; Как вы преодолеваете это? – user805981 2 February 2016 в 06:51
  • 4
    такой же здесь @ пользователь805981 – anvd 14 August 2018 в 14:15
  • 5
    @anvd Является ли ваш объект формы саморазрушимым JSON? – AlexLordThorsen 14 August 2018 в 14:57

Если у вас нет причин беспокоиться об удержании POST ваших данных формы, вы можете использовать скрытые поля форм во втором и третьем представлениях для передачи данных. Подумайте об этих строках ...

forms.py
# override EACH form's init to change the widget for each field to a hidden widget if is_hidden kwarg passed. 

class form_step_1(forms.Form):

    def __init__(self, *args, **kwargs):
        is_hidden = kwargs.pop('is_hidden', None)
        super(FormName, self).__init__(*args, **kwargs)
        if is_hidden:
            for field in self.fields:
                self.fields[field].widget = forms.HiddenInput()

# Be sure to do this for each form with hidden input needed


views.py

@app.route('/form/step1', methods=['GET', 'POST'])
def form_step1():
    form1 = form_step_1(request.POST)
    ...validate()...
    return render_template('register.html', {'form':form1})  

@app.route('/form/step2', methods=['GET', 'POST'])
def form_step2():
    form1 = form_step_1(request.POST, is_hidden=True)
    hidden_forms =[form1]
    form2 = form_step_2(request.POST)
    ...validate()...
    return render_template('register.html', {'form':form2, 'hidden_forms':hidden_forms})

@app.route('/form/step3', methods=['GET', 'POST'])
def form_step3(): 
    form1 = form_step_1(request.POST, is_hidden=True)
    form2 = form_step_2(request.POST, is_hidden=True)
    hidden_forms =[form1, form2]
    form = form_step_3(request.form)
    ...validate()...
    if form.is_valid():
        # do stuff, save to DB
        form1.save()
        form2.save()
        form3.save()
        return HttpReturnRedirect('/success_page/') # Always Redirect after posting form
    # if not valid, show again.
    return render_template('register.html', {'form':form, 'hidden_forms':hidden_forms })


template.html (assuming you are using a single template for each page

<form action="." etc>
    {% csrf_token %}
    {{ form }}
    {% for each_form in hidden_forms %}
        {{ each_form }}

    <!-- your submit button -->
</form>

Теперь, когда ваша форма переходит к POST на шаге 3, если она действительна, доступны данные каждой формы из предыдущих шагов.

Если вы хотите найти безрассудное решение (требуется немного больше работы), посмотрите на Django FormWizard

0
ответ дан Ian Price 22 August 2018 в 09:08
поделиться
  • 1
    скрытые формы кажутся еще хуже, чем сеансы. Во всяком случае, я говорю о фляге и wtforms, а не джанго. – user455318 20 October 2014 в 09:11
Другие вопросы по тегам:

Похожие вопросы: