How to send multiple input field values with same name? - python

I have m2m field, lets say it have name 'relations', so i want to allow user to send as many relations as he wants. I add new input to html with javascript with same name, like so
<input type='text' name='relations' value='a' />
<input type='text' name='relations' value='b' />
in cleaned_data i receive only value of second input ('b'). How to receive both?

I don't know how to do that with Forms, but if you want to grab the values in the raw way, here's how I'd do:
relations = request.POST.getlist('relations')

You don't need to grab all the raw values, you can just get the specific data by using element name like this:
relations = request.form.getlist('relations')
That will return a list of values in the relations input.

this generate a list, you can manipulate in for
request.POST.getlist('relations')

Related

Retail-rendered deform Form (using form attribute) - processing of date is unreliable

Quick summary: How do I ensure correct order of values in request.POST?
I'm using a HTML table (augmented using DataTables to hide columns etc, with the only effect of that being that hidden columns are not included in the call to 'submit') and rendering one deform Form per row.
As deform does not directly support split forms using the form attribute I manually insert form=my_desired_unique_id into all relevant elements. This works fine for simple elements like <input> and <textarea>, the values show up in request.POST.items() and validate fine.
For the deform date-picker things are a bit more complicated though. form['datecolumn'].serialize will generate something like this:-
<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>
There's 3 inputs there (and a fourth hidden one gets added in the rendered HTML with the name 'date_submit'). The visible input's value does not change when the user selects a new date, but the new hidden one's does. On a submit, somehow that value is passed on to the main 'date' input (some js which I don't have a handle on).
The resulting request.POST.items() contains these three elements from the date input:-
('__start__', 'datecolumn:mapping')
('date', '2017-02-24') (this is the newly selected date)
('__end__', 'datecolumn:mapping')
My issue here is that the order of these values is unreliable. On the same page and form, clicking submit multiple times will result in different orders of values in request.POST.items() (all values, not just the date related ones). If the resulting order is as above, things work fine, but if the order is different (say end is before start, or date is after or before both) then I either get a ValueError raised or a validation failure.
I could possibly iterate through request.POST.items() first and ensure the right arrangement, but I want two date pickers in this form, and I have no way of knowing which date field belongs to which pair of __start__ and __end__ markers.
Is there any way to control the order of elements in a POST before it's sent to my view code?
The hack I came up with (will accept any better answers that this!) involves two parts.
Tag each date element (I name all my date elements as *_date) uniquely in my template.
Use the template to re-generate the appropriate POST items.
Specifically, for step one I generate the serialized widget using this function:-
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
The form is the created form instance, elem_name ends with 'date' for datepicker elements, and formid is unique to each form on the page (of which there are many in my page). Lines 2 and 3 insert formid where appropriate, and the if marks datepicker elements.
For step 2 I first remove all __start__ and __end__ elements from request.POST, then find the elements in request.POST which end with date and use them to append (in the right order) elements to 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)
Again, this is obviously a hack/workaround, so something a bit more... elegant would be appreciated.

Web2py AJAX value

I have a list of Projects in my view and I would like to dynamically generate individual pages for each one.
My view:
{{for i in project_list:}}
<ul>
<input id="hello" type="hidden" value="{{response.write(i)}}" name="project_Name">
<li><a onclick="ajax('{{=URL('default', 'view_project')}}', ['project_Name'], 'target');">View Project</a></li>
</ul>
{{pass}}
My controller:
def view_project():
print request.vars.project_Name
return dict(name=request.vars.project_Name)
Essentially, I would like to identify each Project by its project_Name.
This is the current output from the controller:
['Customizable logistical service-desk ', 'Extended contextually-based prod
uctivity ', 'Face-to-face modular circuit ', 'Multi-tiered stable intranet
', 'Quality-focused coherent budgetary management ']
Why am I receiving an Array of all project names as output?
I just want to identify each project.
Any advice is appreciated!
The web2py ajax function sends to the server the value of the html element with the name attribute passed in the functions second parameter ("project_Name" in your case), but if there are more than one field with the same name, it will send the values of all of them.
So, you are creating with a loop many fields with the same name, and the ajax function is sending all the values to the server.
You can solve the problem appending a count variable to each field name (and its name on his onclick attribute):
{{count = 1}}
{{for i in project_list:}}
<ul>
<input id="hello" type="hidden" value="{{response.write(i)}}" name="project_Name{{=count}}">
<li><a onclick="ajax('{{=URL('default', 'view_project')}}', ['project_Name{{=count}}'], 'target');">View Project</a></li>
</ul>
{{count += 1}}
{{pass}}
Or use a more clean solution usin the JQuery ajax function
You have:
ajax('{{=URL('default', 'view_project')}}', ['project_Name'], 'target')
You have specified "project_Name" as the form input element from which to extract the value to post. However, there are multiple inputs on the page all with that same name. As a result, the Ajax function serializes all of their values into a single list and posts the whole list.
You could give each input a unique name, but there is a simpler solution. It appears you are using the hidden input elements merely to hold values to be sent by the Ajax function. There is no need for that -- instead, you can simply encode the values directly in the Ajax URL. So, get rid of the input elements and change your ajax call to:
ajax('{{=URL('default', 'view_project', vars=dict(project_name=i)}}', [], 'target')

How to add extra field data to a form field in Wtforms

I am trying to add extra data to a form field in wtforms.
I have to create a text field which has an associated unit with it (eg - meter/sec). How do I add the meter/sec string to the form field?
Is there any way to pass a dictionary or something to add data to the field that i can access in the template?
There is a not very well known parameter, description= to the field constructor. Though it purports to be for help text, the framework itself doesn't care what you put in there (and indeed doesn't use it anywhere at all, other than passing it along.)
So you could do, for example:
class PhysicsForm(Form):
speed = TextField('Speed', description={'unit': 'meters/sec'})
distance = TextField('Distance', description={'unit': 'kilometers'})
Then you could use it in a jinja-style template something like:
{{ form.speed }} <label>{{ form.speed.description.unit }}</label>
footnote There was no real reason for using a dictionary as the value of description - it was merely to illustrate that you can put nearly any value in there, including containers which can hold many values.

pyramid checkboxes

I'm just new to python and pyramid and I'm struggling with how to process the results of a form containing multiple checkboxes in Pyramid.
Here is an excerpt from my form:
<p tal:repeat="category categories">
<input type="checkbox" name="selectedcategories" value="${category.id}"> ${category.name}<br/>
</p>
And here is how I am currently trying to iterate through and process the results:
selectedcategories=request.params['selectedcategories']
for categoryid in selectedcategories:
category = DBSession.query(Category).filter_by(id=categoryid).one()
article.categories.append(category)
As you may have guessed, I'm only getting a maximum of one checkbox recognized no matter how many I select on the form. Django has an option to return the results as a list, but I can't seem to figure out how to do that with Pyramid.
request.params is a multidict. To retrieve multiple values, you can call its getall() method:
selectedcategories = request.params.getall("selectedcategories")

Python / Django - Form Selection Value is Object Id... Can't Get Object

I have a form select box that has values corresponding to objects. The user selects an input and the form submits. I then want to take that value and retrieve the object that has an ID equivalent to the selected form value. However, when I try to do so, I'm getting an error like so:
int() argument must be a string or a number, not 'Cars'
Example:
if form.is_valid():
car = Car.objects.get(id=form.cleaned_data['id'])
I'm guessing the problem is that the returned value is a string and NOT an integer. In PHP this is SIMPLE. How do I typecast or use the returned form value to get an associated object?
Seems as though Django is not returning the value of the form element, but instead the user visible option name...
Form Class:
class CarForm(forms.ModelForm):
class Meta:
model = Car
Html Form:
<form action="">
<select name="id">
{% for car in cars %}
<option value="{{car.id}}">{{car.title}}</option>
{% endfor %}
</select>
</form>
The id field has to be an integer, or a string that can be converted to an integer.
Simple as that!
Somehow, your form.cleaned_data['id'] is returning a model called Cars
Ensure it returns a number if you want to pass it into get(id=
You can use ModelChoiceField instead of generating the select using HTML
in forms.py:
class CarSelectForm(forms.Form):
car = forms.ModelChoiceField(queryset=Car.objects.all(), empty_label=None)
in view.py:
if form.is_valid():
car = form.cleaned_data['car']
This is maybe a bad, but I think working answer. If anyone has a real solution, please post because I still need it.
(I'm using a modelformset, but just a modelform may work the same)
For me, the {{ form.id }} works on the page (puts the id) and comes back correctly in the POST data. However, somewhere along the line it gets converted (as Yuji said in his post) into the model object represented by that id and that is what is in cleaned_data.
In short, change
car = Car.objects.get(id=form.cleaned_data['id'])
to
car = form.cleaned_data['id']
I think it just looks like a string just because when you print or debug, it's using your str or unicode representation.
Repeat: This is almost certainly a side effect or bad way to do things. If I figure out a better way, I'll post it.
I have the same issue... so I tried the following:
ts_1 = form.cleaned_data['lista_trabajos']
ts_2 = request.POST['lista_trabajos']
print(ts_1) # this returns what user sees, ex: 1 - folders
print(ts_2) # this returns value from that option, in my case: 1
Unfortunately, I have been reading that by using raw POST data is not recommended. At the moment, I cannot figure out how to validate and get the raw POST data by using something similar to "clean_data".
You can read about this in: https://books.google.com.ar/books?id=8sU7DwAAQBAJ&pg=PA229&lpg=PA229&dq=form+cleaned_data+to+get+raw+post+data&source=bl&ots=RN9WKRaGJs&sig=QpSoPdI9YSHSNk0zAQIO8phSbOw&hl=es&sa=X&ved=0ahUKEwiBouHattnaAhULFZAKHUKmA4QQ6AEIRzAD#v=onepage&q=form%20cleaned_data%20to%20get%20raw%20post%20data&f=false

Categories

Resources