MultipleChoiceField : check all if nothing is checked - multiplechoicefield

What I want to do seems simple : I have a MultipleChoiceField in a django form which proposes the id and pseudo of all books in a model named Dico :
class FiltreMonoForm(forms.Form):
dico_choices = []
for dic in Dico.objects.all().order_by('pseudo'):
dico_choices.append((dic.id, dic.pseudo))
dico_choices=tuple(dico_choices)
dicos = forms.MultipleChoiceField(required=False, widget=forms.CheckboxSelectMultiple, choices=dico_choices, initial=[c[0] for c in dico_choices], label="Diccionaris sorsas")
I get this form back in a view :
def monollist(request):
if request.GET:
getcopy = request.GET.copy()
form = FiltreMonoForm(getcopy)
dicos = form.cleaned_data['dicos']
else:
form = FiltreMonoForm()
I would like to have all the books checked if the user have checked none of them. Something like :
if request.GET:
getcopy = request.GET.copy()
form = FiltreMonoForm(getcopy)
dicos = form.cleaned_data['dicos']
for dic in Dico.objects.all().order_by('pseudo'):
dico_choices.append((dic.id, dic.pseudo))
dico_choices=tuple(dico_choices)
if len(dicos)==0:
form['dicos']=dico_choices
But I can't find how to change the value of the MultipleChoicesField. I tried with
form.data['dicos']=dico_choices
but it seems that I can only give one value to form.data['dicos'], it won't accept lists nor tuples.
I tried to override the __init__ method in my form in adding
self.data.update(dicos=dico_choices)
but I have the same issue, it works only if dico_choices is a single value.
Do you have any idea how to override my MultipleChoiceField with multiple values ?
Thanks

if 'dicos' not in getcopy:
for dic in Dico.objects.all():
getcopy.update({'dicos': dic.id})

Related

Flask Wtforms FieldList(FormField to populate a SelectField with choices is not appending to form

I am trying to populate a form using a combination of str and lists. The string fields in the form populate without issue. However the selectfield in the form appears to only display the last entry given in the list it receives as if it's overwritten the previous contents in the form.
If the list (later converted to tuple) is :
[['one#email.com', 'two#email.com'], ['one#2email.com', 'two#2email.com]]
What gets displayed in the choices throughout the form will be:
one#2email.com
two#2email.com
I've tried various iterations but no luck so far.
class BulkAddFields(Form):
ip_addr = StringField(label='ip_addr')
dom_emails = StringField('dom_emails')
new_emails = SelectField('new_emails', coerce=int)
class BulkAddForm(FlaskForm):
incidents = FieldList(FormField(BulkAddFields))
submit = SubmitField('Submit')
form = BulkAddForm()
# i = str, d = str, n=list
for i, d, n, in data:
form.ip_addr = i
form.dom_emails = d
form.incidents.append_entry(form)
email = list(enumerate(n))
for sub_form in form.incidents:
sub_form.new_emails.choices = email
I've added a picture/link that shows how the string fields are replicated down the page as expected but the selectfield replicates the last item in the list only.
enter image description here
Try changing it from
new_emails = SelectField('new_emails', coerce=int)
to
new_emails = SelectField('new_emails', coerce=str)
You should then be able to pass the choices as a list. Let me know if that helps.
Below is the code that ended up working. Although I don't like adding a field to the form each time, knowing that the field is going to exist everytime I wanted to include it in the BulkAddFields but couldn't figure out how.
class BaseForm(FlaskForm):
#classmethod
def append_field(cls, name, field):
setattr(cls, name, field)
return cls
class BulkAddFields(BaseForm):
ip_addr = StringField(label='ip_addr')
dom_emails = StringField('dom_emails')
class BulkAddForm(BaseForm):
incidents = FieldList(FormField(BulkAddFields))
submit = SubmitField('Submit')
form = BulkAddForm()
for i, d, n, in data:
email = list(enumerate(n))
bulkfields = BulkAddFields()
bulkfields = bulkfields.append_field('new_emails',
SelectField('New Emails', choices=email))
form.ip_addr = i
form.dom_emails = d
form.incidents.append_entry(form)
Picture with repeating selectfield for New Emails

Create values in Many2one field From many2many wizard (or) TransientModel

From Following code I Created values in Many2one field From many2many tag field of wizard (or) TransientModel
def add_employee_btn(self):
record = self.env['add.employees'].browse(self._context.get('active_id'))
for e in self.employee_ids:
vals={'employee_names':e.name,
'issue_id': record.id}
res = self.env['issues.issues'].create(vals)
I need Another method Using List append like this..
def add_employee_btn(self):
list = []
record=self.env['add.employees'].browse(self._context.get('active_id'))
for e in self.employee_ids:
list.append(({0,0,{'employee_names':e.name,
'issue_id': record.id}}))
But getting Error in this If some one knows fix it...
def add_employee_btn(self):
list = []
record=self.env['add.employees'].browse(self._context.get('active_id'))
for e in self.employee_ids:
list.append([0,0,{'employee_names':e.name,
'issue_id': record.id}])
Please, try this it would may help you to solve error.

How to pass ChoiceField choices to formset?

The name works fine, but I can figure out how to pass the list of choices in the same way. The fields for those come up blank. In debugging, the choices appear properly set up.
forms.py
class MatchSheets(forms.Form):
""" Match sheets """
name = forms.CharField()
propertyuser = forms.ChoiceField(choices=(), required=False)
SheetSet = formset_factory(
MatchSheets,
extra=0
)
views.py
sheets = PropSheetNames.objects.filter(owner=request.user,
sponsoruser=sponsoru_id)
props = SponsorsUsers.objects.filter(owner=request.user,
id=sponsoru_id).all()
initial_set = []
choiceset = (((prop.id), (prop.alias)) for prop in props[0].properties_user.all())
for sh in sheets:
initial_set.append(
{'name': sh.name,
'propertyuser.choices': choiceset}
)
form = SheetSet(request.POST or None, initial=initial_set)
I know someone will point out this could be done better with a modelformset_factory for the whole thing, or modelselect for the propertyuser, but I ran into issues with both, and just doing it manually gave me more flexibility.
First, this was wrong (corrected):
choiceset = [((prop.id), (prop.alias)) for prop in props[0].properties_user.all()]
Then added this below form=
for f in form:
f.fields['propertyuser'].choices = choiceset
Was able to take it further, defaulting the choices to the value of the name field as well:
initial_set = []
nameset = [prop.alias for prop in props[0].properties_user.all()]
choiceset = [((prop.alias), (prop.alias)) for prop in props[0].properties_user.all()]
choiceset.append(('', '----'))
and then
for f in form:
f.fields['propertyuser'].choices = choiceset
if f.initial['name'] is not None and f.initial['name'] in nameset:
f.fields['propertyuser'].initial = f.initial['name']
Now the user just needs to handle the mismatched pairs, and done. These were the reasons I was pushed out of using Model options, at least at my ability level.

sub-classing a peewee field type to add behavior

I am trying to add the required behavior to a CharFiled or TextField so I can store a list of lists and retrieve it as a list of lists again. I am not asking for a solution rather I would like to see an example where a subclassing of an already supported field type is done as I didn't find any in the documentation or the Internet.
Do I have to do it as explained in the documents for creating a custom type?
for example:
class mylistoflists(TextField):
if yes, then what do I have to assign to field_type?
Example code (see tests/fields.py for full example):
class ListField(TextField):
def db_value(self, value):
return ','.join(value) if value else ''
def python_value(self, value):
return value.split(',') if value else []
class Todo(TestModel):
content = TextField()
tags = ListField()
class TestCustomField(ModelTestCase):
requires = [Todo]
def test_custom_field(self):
t1 = Todo.create(content='t1', tags=['t1-a', 't1-b'])
t2 = Todo.create(content='t2', tags=[])
t1_db = Todo.get(Todo.id == t1.id)
self.assertEqual(t1_db.tags, ['t1-a', 't1-b'])
t2_db = Todo.get(Todo.id == t2.id)
self.assertEqual(t2_db.tags, [])
t1_db = Todo.get(Todo.tags == Value(['t1-a', 't1-b'], unpack=False))
self.assertEqual(t1_db.id, t1.id)

How to get Id from Object in Odoo 10?

This is my structure:
class Imprint_Location(models.Model):
_name = 'imprint.location'
name = fields.Char()
product_id = fields.Many2one('product.template')
class Imprint_Charges(models.Model):
_name = 'imprint.charge'
_rec_name = 'location_id'
product_id_c = fields.Many2one('product.template', required=True)
location_id = fields.Many2one('imprint.location', required=True)
#api.multi
#api.onchange('product_id_c', 'location_id')
def product_filter(self):
res = {}
print '\n\n-------\n\n', self, self.product_id_c, '\n\n-------\n\n'
if self.product_id_c:
res['domain'] = {'location_id': [('product_id', '=', self.product_id_c.id)]}
print res
return res
class Product_Template(models.Model):
_inherit = 'product.template'
imprint_location_ids = fields.One2many('imprint.location', 'product_id')
sale_imprint_charge_ids = fields.One2many('imprint.charge', 'product_id_c')
Now i have defined a page in product.template and inside the page is sale_imprint_charge_ids which is in <tree editable="bottom"> and i am not selecting the product_id_c field[also this field doesn't show up in the tree defined].
Now my problem here is that when i select this from the form view which i defined for imprint.charge the method product_filter works fine, but when i enter from the product.template then i get a error saying
TypeError: <odoo.models.NewId object at 0x7fbb8bc21b90> is not JSON serializable
Because from product.template if passes the object <odoo.models.NewId object at 0x7fbb8bc21b90> , so if print self.product_id_c then it prints product.template(<odoo.models.NewId object at 0x7fbb8bc21b90>) so this is not serializable. i have tried doing self.product_id_c.ids which give output empty list [].
So how do get the product.template id from the object or pass the id itself overriding some method.
You should improve couple of following points.
res['domain'] = {'location_id': [('product_id', '=', self.product_id_c.id)]}
return res
study some search() method of ORM
Try with following code:
#api.multi
#api.onchange('product_id_c', 'location_id')
def product_filter(self):
res = {}
if self.product_id_c:
self.location_id = False
#search product_template in imprint.locationwith table and limit we will get only record if related record found
location_id = self.env['imprint.location'].search([('product_id', '=', self.product_id_c.id)], limit=1)
if location_id:
#location_id.ids will give you something like [2] so we need to set value as 2
self.location_id = location_id.ids[0]
EDIT:
As per your first comment, you need a list of related location then we should following trick.
Remove product_filter() method
Add domain in imprint.charge object view file
For example:
<field name="location_id" domain="[('product_id', '=', product_id_c)]"/>
Afterwards, Restart Odoo server and upgrade your custom module.
When creating a brand new record Odoo creates that wierd <odoo.models.NewId object at 0x7fbb8bc21b90> object. After you have written the record this id gets turned into the normal ids that you are used to (an integer). In this situation you have a function which (not unreasonably) expects a real id value at a point when no such value really exists. You need to provide a fallback, such as evaluating if the id is an integer and providing an alternate value in that circumstance. Although your function seems to return an object which I dont quite know what you are expecting to happen. If you wish to modify the value of one of your fields I would modify the values of the self object rather that returning an object.

Resources