Flask: How can I store user's form-input so that it can be retrieved two requests later - forms

I am working on a logistics website using Flask.
On route /step1 the user fills in a form detailing n parcels and their attributes.
The form is submitted and a POST request is sent to /step2 with the following data:
*weight1, length1, width1, height1,
weight2, length2 ...
...
...
*weightn, lengthn, widthn, heightn,
In /step2 the user fills in the sender and recipient addresses.
This form is submitted as a POST request to /process-order
Here's the problem:
How does my process_order view retrieve the data provided in both /step1 and /step2
I can think of three solutions - listed below - but I only know how to go about the first one.
storing the data submitted in step1 form inside hidden inputs and sending this to the form in step2.html and subsequently retrieving this data from the request sent to process_order and storing them as an array.
Caching
flask.g
N.B. This is my very first Flask project and I have zero experience with caching. So please dumb things down for me.
Update
Here's my actual code:
#main.route('/order', methods=['POST'])
def order():
# this function is invoked when user submits a form from the home page
country_from = request.form['country_from']
country_to = request.form['country_to']
data = request.form
parcels = []
for i in range(1, int(data['parcel_count']) + 1):
parcel = Parcel(
weight=data['weight{}'.format(i)],
length=data['length{}'.format(i)],
width=data['width{}'.format(i)],
height=data['height{}'.format(i)],
)
parcels.append(parcel)
weight_units = data['units']
if weight_units == 'kg':
distance_units = 'cm'
else:
distance_units = '"'
return render_template('order.html',
countries = COUNTRIES,
country_from = country_from,
country_to = country_to,
parcels = parcels,
weight_units = weight_units,
distance_units = distance_units,
)
#main.route('/process-order', methods=['POST'])
def process_order():
data = request.form
parcels = []
# pending
# how can I retrieve the parcels array again?
Note that my view functions are being invoked from the action attribute of the forms in my templates (not included here).

Also, you can pass the inputs between steps as parameters as follows
#app.route('/step1', methods=['GET', 'POST'])
def step1():
parcels=[(11,12,13,14),(21,22,23,24),(31,32,33,34)] # contain list of weights, lengths, widths, heights,
weight_units ='kg' # another data to pass
return redirect(url_for('step2',x=parcels,y=weight_units ))
#app.route('/step2/<x>/<y>', methods=['GET', 'POST'])
def step2(x,y):
print(x) # console output
print(y)
return 'ok'
and so on, send all to the next one with more parameters

Related

Construct a form on the basis of row inside database. Django

# models.py
from django.db import models
from django.forms import ModelForm
question_choices = (
(1, 'yes/no'),
(2,'text'),
(3,'numberic'),
)
class Question(models.Model):
title = models.CharField(max_length=500,blank=False)
responseType = models.SmallIntegerField(choices=question_choices,blank=False
,default=2)
mandatory = models.BooleanField(default=True)
def __str__(self):
return self.title
answer_choices = (
(1, 'YES'),
(2,'NO'),
)
class Response(models.Model):
questionId = models.ForeignKey(Question,on_delete=models.CASCADE)
answerType1 = models.CharField(max_length=4,choices=answer_choices,blank=True)
answerType2 = models.TextField(max_length=500,blank=True)
answerType3 = models.IntegerField(blank=True)
def __str__(self):
return self.id
Assume two buttons on UI. 1. Create questions 2. Fill Questions.
When user will click on 1st button(Create questions), according to Question model user will be able to save some question to the DB.
When user clicks on 2nd button (Fill Questions)
If data is there in DB then , create a form according to row of Question model and send it to user such that after getting the response from user data will be saved inside Response model.
For reference i have added screenshot of Question model from admin pannel.
I wanted to create a form according to every row.

Limiting a Django form's ManyToManyField queryset in a formtools wizard based on selection on previous form

I'm using a SessionWizardView from django-formtools to construct a two-form wizard. The challenge I'm facing is that I need to reference the input from the first form to limit the available querysets on the second form.
To make it more interesting, I'm using crispy forms for layout and the queryset needs to be limited by a method on a related item.
Here's the (much simplified) gist of where I'm at:
Models
class Product(models.Model):
# pk, name, etc....
catalogitem = ForeignKey("myapp.CatalogItem")
colors = ManyToManyField("myapp.Colors")
class Colors(models.Model):
# pk, name, etc....
class CatalogItem(models.Model):
# Colors are stored within CatalogVariants, which I've left
# as a blackbox in this example, since they are retrieved as
# a queryset on this model with this method:
# pk, name, etc....
def get_colors(self):
# Returns a queryset of color objects.
Views
ProductFormWizard(SessionWizardView):
form_list = [
productFormWizard_Step1,
productFormWizard_Step2,
]
def get_context_data(self, **kwargs):
# ...
pass
def get_form_initial(self, step):
initial = {}
# ...
return self.initial_dict.get(step, initial)
def process_step(self, form):
if self.steps.step1 == 1:
pass
return self.get_form_step_data(form)
def done(self, form_list, **kwargs):
return render(self.request, 'done.html', {
'form_data': [form.cleaned_data for form in form_list],
})
Forms
productFormWizard_Step1(forms.ModelForm):
# Defines a form where the user selects a CatalogProduct.
model = Product
productFormWizard_Step2(forms.ModelForm):
"""
Defines a form where the user chooses colors based on
the CatalogProduct they selected in the previous step.
"""
model = Product
Based on research via the Googles and some SO questions (none of which were =directly= related), I'm assuming I need to set the .queryset property on the colors field, but I'm not exactly sure where to do that. Two thoughts:
I would guess it goes in .get_form_initial() somehow, but I'm at a loss as to the best way to achieve that.
Alternatively, the appropriate code might go into the productFormWizard.get_context_data() method somehow.
Within .get_form_initial(), I can do something like this:
if step == '1':
itemID = self.storage.get_step_data('0').data.get('0-pfProduct', "")
if itemID:
obj = CatalogItem.objects.get(id=itemID)
initial['colors'] = obj.get_get_colors()
However, this just selects the available related items... it doesn't limit the list.
Additional Info
Python == 3.5.3
Django == 1.10.6
django-crispy-forms == 1.6.1
django-formtools == 2.0
The solution is to override the .get_form() method on the View:
def get_form(self, step=None, data=None, files=None):
form = super(bzProductFormWizard, self).get_form(step, data, files)
if step == '1':
past_data = self.get_cleaned_data_for_step('0')
product = past_data['product']
form.fields['colors'].queryset = ... #CUSTOM QUERYSET
return form

Modifying individual field form inputs (CSS, Placeholder, etc) Drupal 7 registration form preprocess

I'm attempting to preprocess CSS and placeholder etc to the form inputs for the Registration Form. I'm manually rendering each field input on the registration form.
The following code works fine for email or password, but not 'custom fields'.
$form['account']['mail']['#attributes']['placeholder'] = t('Email address');
$form['account']['mail']['#attributes']['class'][] = 'email-input';
$form['account']['mail']['#title_display'] = "invisible";
$form['account']['mail']['#description'] = t('');
When I apply the same to the custom fields, it won't apply.
I have looked through the user module and printed avialable varibles
$form['field_first_name']['#attributes']['placeholder'] = t('First Name');
$form['field_first_name']['#attributes']['class'][] = 'first-name-input';
$form['field_first_name']['#title_display'] = "invisible";
$form['field_first_name']['#description'] = t('');
I found multiple mentions of field_first_name in the variable print out, but I'm unable to modify the text inputs directly.

On a HTML Edit form, what is a good approach to have both reset and remember the posted values features?

I have a form which has both server side and client side validation.
It is an edit form, so the original user values are originally pre-populated.
e.g. The original pre-populated values are:
username = yeo
surname = yang
phonenumber = 11-12345
Now, the user edits to the below and submits.
e.g. The edited submitted values are:
username = yeoNew
surname = yangNew
phonenumber = 12-1111
This gets submitted to the serverside and fails the serverside validation because the phonenumber starting with 12 is not allowed.
Anyway, so the form is displayed back to the user as
e.g. The redisplayed form values are:
username = yeoNew
surname = yangNew
phonenumber = 12-1111
This is because my form allows the user to remember their submitted values.
At this stage, I'd like to allow the user to have the ability to reset the form values to the original values using clientside javascript. This is like a reset feature.
e.g. The reset button will restore the form values to:
username = yeo
surname = yang
phonenumber = 11-12345
The reason for this reset feature is that I want the user to have the option to edit the phonenumber again from the original values.
My question is:
What is a good way to keep track of the original values within the HTML so that I can restore it with javascript?
I'm thinking a new attribute called orig='' within the form elements which will store this value.
Is that a good idea?
Any other approaches?
thanks
I would use the HTML5 local storage.
See http://www.w3schools.com/html/html5_webstorage.asp
Using jquery I would do it this way:
<script type="text/javascript">
function load() {
if (localStorage["username"]) {
$('#username').val(localStorage["username"]);
}
if (localStorage["surname"]) {
$('#surname').val(localStorage["surname"]);
}
if (localStorage["phone"]) {
$('#phone').val(localStorage["phone"]);
}
}
function save() {
localStorage["username"] = $('#username ').val();
localStorage["surname"] = $('#surname').val();
localStorage["phone"] = $('#phone').val();
}
</script>

How to populate zend form field using session?

I am using sessions to populate a multi select box with options in my Zend application.
The user selects one or more options and fills in other fields on the form and then submits. If the user didn't select all of the options in the multi select then the form is displayed again but the multi select only has the options that the user did not select the last time. This process goes on until there are no more options from the multi select left to process.
Here is the code I use to get rid of the options that have already been processed so that they are not used to populate the multi select box:
if($form_successful){
// TODO remove $post['keyword_names'] (i.e. already processed) from $keyword_names (that come from $_SESSION)
$keyword_names = array_diff($keyword_names, $post['keyword_names']);
print_r($keyword_names);
if(is_array($keyword_names) && !empty($keyword_names)){
// save updated $keyword_names into $_SESSION['workflow1']
$session = new Zend_Session_Namespace('workflow1');
$session->keyword_names = $keyword_names;
// set flag to false so that we display form again
$form_successful = false;
}else{ // all keywords have been assigned
// go to next step
$this->_redirect('/workflow-1/step-'.($step+1).'/');
}
}
print_r($keyword_names); displays the correct options, however when the form is loaded when the user submits, the multi select displays the options that were there from the begining ie the options the user has just selected and submitted are not being taken out of the multi select, it is only when the user submits the form again then the multi select box updates.
Appreciate the help.
Solved the issue by making use of URL parameters. Here is the code (might differ a lot from what I posted first because some big changes were made):
// after successful form submission
if($form_successful){
// remove $post['keyword_names'] (i.e. already processed) from $keyword_names (that come from $_SESSION)
$keyword_names = array_diff($keyword_names, $post['keyword_names']);
// save remaining $keyword_names into $_SESSION['workflow1']
$session = new Zend_Session_Namespace('workflow1');
$session->keyword_names = $keyword_names;
if(is_array($keyword_names) && !empty($keyword_names)){
// redirect to the same step again - to ensure that the form will reflect (in select lists) newly created AdGroup and/or Campaign
// GET parameteres ($params_array) provide a way to remember user's choice
$params_array = array();
if(!empty($post['match_type_id'])){
$params_array['match_type_id'] = $post['match_type_id'];
}
if(!empty($post['with_permutations'])){
$params_array['with_permutations'] = $post['with_permutations'];
}
if(!empty($ad_group_id)){
$params_array['ad_group_id'] = $ad_group_id;
}
$this_step_url = UrlUtils::assemble('', $this->getRequest()->getActionName(), $this->getRequest()->getControllerName(), $this->getRequest()->getModuleName(), $params_array);
$this->_redirect($this_step_url);
}else{ // all keywords have been assigned
// go to next step
$this->_redirect('/workflow-1/step-'.($step+1).'/');
}
}
So you don't have any code about Zend_Form object here. How do you populate the form element? If you post your class code which extends Zend_Form (or any other code dials with your form) then I may help. But in any case you can populate your multiselectbox with setMultiOptions() method or addMultiOption() for each item in multiselectbox.