WTForms FieldList with optional fields - python

I have the following form,
class AddForm(wtf.Form):
tags = TagListField("Tags (comma separated)", validators=[wtf.Required()])
question = wtf.TextField("Question", validators=[wtf.Required()])
answers = wtf.FieldList(wtf.TextField("Answer", validators=[wtf.Required()]), min_entries=2, max_entries=5)
And I have a form setup to display this form along with a button that adds more "answers" inputs dynamically (by the user clicking a button). However, when the form gets submitted, any fields that are added but not filled in are considered errors.
Specifically, if I have 3 inputs for "Answer", but I only fill in the first two, then the third one comes up as an error, even though I have specified that the minimum number of entries is 2. It seems like it should ignore this data.
Since I am using this with Flask I am going to just modify the request.form data to ignore blank fields. Is there something I'm missing?

May be your the
validators=[wtf.Required()])
is an issue ? Have you tried changing it to
validators=[wtf.Optional()])

Related

odoo 9 Automatically changing the selection field and radio button field depends on the changed other selection field

I need a help please.
So I wanted when I change the Internal Category (field name is categ_id) value to 500 final product,
and then the Routes field changes to :
Manufacture checked,
Make To Order checked,
Buy checked
and also the Value of Tracking field is changes as well to:
By Lots checked
How can I do that? Any suggestion ? Or my is it my question are not clear enough ?
Sorry for asking , I never done this before so yeah kind a confusing.
Here I got the picture the interface and the information about the field as well.
Routes field name
Tracking field name
Please anyone kindly to help me. I am so confused.
You could achieve this by using api onchange in Odoo 9.
#api.onchange('categ_id')
def onchange_categ_id(self):
for record in self:
# I prefer to check by id, but here I show how to check by string name in case you want it
if record.categ_id.name == '500 final product':
# because route_ids is many2many field,
# you need special commands to change the value
# here I use (6, _, ids) to set value.
# But before that, you have to get the ids of the routes you want from model stock.location.route
# (you could use search method to get the ids)
record.route_ids = [(6,0, list_of_id)]
record.tracking = 'lot'
...
You could refer to Odoo Doc to learn more about O2m and M2m commands

python database table linking

I'm new to Python and I'm trying to make a simple bulletin board system app using web2py. I am trying to add a post into a certain board and I linked the post and board by including the following field in my post table: Field('board_id', db.board). When I try to create a post inside a particular board it gives me an error: "OperationalError: no such column: board.id". My code for create_posts:
def add_post():
board = db.board(request.args(0))
form = SQLFORM(db.post)
db.pst.board_id.default = db.board.id
if form.process().accepted:
session.flash = T('The data was inserted')
redirect(URL('default', 'index'))
return dict(form=form, board=board)
When I try to do {{=board}} on the page that shows the posts in a certain board, I get Row {'name': 'hi', 'id': 1L, 'pst': Set (pst.board_id = 1), 'description': 'hi'} so I know it's there in the database. But when I do the same thing for the "add post" form page, it says "board: None". I'm extremely confused, please point me in the right direction!
There appear to be several problems with your function. First, you are assigning the default value of the board_id field to be a Field object (i.e., db.board.id) rather than an actual id value (e.g., board.id). Second, any default values should be assigned before creating the SQLFORM.
Finally, you pass db.post to SQLFORM, but in the next line, the post table appears to be called db.pst -- presumably these are not two separate tables and one is just a typo.
Regarding the issue of {{=board}} displaying None, that indicates that board = db.board(request.args(0)) is not retrieving a record, which would be due to request.args(0) itself being None or being a value that does not match any record id in db.board. You should check how you are generating the links that lead to add_post and confirm that there is a valid db.board id in the first URL arg. In any case, it might be a good idea to detect when there is no valid board record and either redirect or display an error message.
So, your function should look something like this:
def add_post():
board = db.board(request.args(0)) or redirect(URL('default', 'index'))
db.pst.board_id.default = board.id
form = SQLFORM(db.pst)
if form.process(next=URL('default', 'index'),
message_onsuccess=T('The data was inserted'))
return dict(form=form, board=board)
Note, if your are confident that links to add_post will include valid board IDs, then you can eliminate the first line altogether, as there is no reason to retrieve a record based on its ID if the only field you need from it is the ID (which you already have). Instead, the second line could be:
db.pst.board_id.default = request.args(0) or redirect(URL('default', 'index'))

WTForms Set input field after post

For below example:
Product(form):
product = TextField('name')
If i set this field in GET action
form.product.data= "123",
render is "123".
However, if i try set this value after POST action,
i allways get value form POST
How can i set this value (rerender) after POST ?
I wanted change only particulars fields, but rest keep from POST.
I have noticed that data from POST has additional field "raw_data" and set form.product.data fiels hasn't done (re)render. Solution proved to be clear
form.product.raw_data = None
form.product.data = 123
render new value
Maybe little bit "elegant" , but works !!!
Are you asking how to clear form data from the form after a user has submitted it?
In that case you could re-initialize the form
when you do
product = Product(request.POST)
It will fill the data that the user submitted.
product = Product()
This will clear the data.
Note:
use 4 spaces for every line of the code, so it is displayed well.

Can a formfield be selected w/mechanize based on the type of the field (eg. TextControl, TextareaControl)?

I'm trying to parse an html form using mechanize. The form itself has an arbitrary number of hidden fields and the field names and id's are randomly generated so I have no obvious way to directly select them. Clearly using a name or id is out, and due to the random number of hidden fields I cannot select them based on the sequence number since this always changes too.
However there are always two TextControl fields right after each other, and then below that is a TextareaControl. These are the 3 fields I need access too, basically I need to parse their names and all is well. I've been looking through the mechanize documentation for the past couple hours and haven't come up with anything that seems to be able to do this, however simple it should seem to be (to me anyway).
I have come up with an alternate solution that involves making a list of the form controls, iterating through it to find the controls that contain the string 'Text' returning a new list of those, and then finally stripping out the name using a regular expression. While this works it seems unnecessary and I'm wondering if there's a more elegant solution. Thanks guys.
edit: Here's what I'm currently doing to extract that info if anyone's curious. I think I'm probably just going to stick with this. It seems unnecessary but it gets the job done and it's nothing intensive so I'm not worried about efficiency or anything.
def formtextFieldParse(browser):
'''Expects a mechanize.Browser object with a form already selected. Parses
through the fields returning a tuple of the name of those fields. There
SHOULD only be 3 fields. 2 text followed by 1 textarea corresponding to
Posting Title, Specific Location, and Posting Description'''
import re
pattern = '\(.*\)'
fields = str(browser).split('\n')
textfields = []
for field in fields:
if 'Text' in field: textfields.append(field)
titleFieldName = re.findall(pattern, textfields[0])[0][1:-2]
locationFieldName = re.findall(pattern, textfields[1])[0][1:-2]
descriptionFieldName = re.findall(pattern, textfields[2])[0][1:-2]
I don't think mechanize has the exact functionality you require; could you use mechanize to get the HTML page, then parse the latter for example with BeautifulSoup?

Django: How to modify a text field before showing it in admin

I have a Django Model with a text field. I would like to modify the content of the text field before it's presented to the user in Django Admin.
I was expecting to see signal equivalent of post_load but it doesn't seem to exist.
To be more specific:
I have a text field that takes user input. In this text field there is a read more separator. Text before the separator is going to go into introtext field, everything after goes into fulltext field.
At the same time, I only want to show the user 1 text field when they're editing the article.
My plan was to on_load read the data from introtext and fulltext field and combine them into fulltext textarea. On pre_save, I would split the text using the read more separator and store intro in introtext and remainder in fulltext.
So, before the form is displayed, I need to populate the fulltext field with
introtext + '<!--readmore-->' + fulltext
and I need to be able to do this for existing items.
Have a look into Providing your own form for the admin pages.
Once you have your own form, you can use the default param in the form to provide the initial value you want. See the docs on the Initial param for the form field. As this link will show you, it is possible to use a callable or a constant as your initial value.
There is no post_load because there is no load function.
Loading of the instance is done in init function, therefore the right answer is to use post_init signal.

Categories

Resources