Reputation: 11919
I'm trying to save multiple checkbox selections on a Charfield, but I cannot bypass the message:
Select a valid choice. ['...', '...', '...'] is not one of the available choices.
I want to save the selected values with pipe separed values in a single attribute in the database. I have already created "clean" methods for the 2 MultipleChoiceFields, but it seems the error occurs AFTER the clean itself. There is a check if the resulting string is present in the list os possible values. That is what I want to override. Here is the code I'm using:
estomatologia_form.py
class EstomatologiaForm(forms.ModelForm):
sinais_e_sintomas_locais = forms.MultipleChoiceField(
choices=Estomatologia.TIPOS_SINAIS_E_SINTOMAS,
widget=forms.CheckboxSelectMultiple(),
label='Sinais e Sintomas locais (marque todas as opções válidas) *',
)
...
def __init__(self, *args, **kwargs):
if 'instance' in kwargs:
if kwargs['instance'] is not None:
kwargs['initial'] = {}
ssl = kwargs['instance'].sinais_e_sintomas_locais.split('|')
cp = kwargs['instance'].comorbidades_paciente.split('|')
kwargs['initial']['sinais_e_sintomas_locais'] = ssl
kwargs['initial']['comorbidades_paciente'] = cp
super(EstomatologiaForm, self).__init__(*args, **kwargs)
#OBS: campos para MultipleChoiceField não devem receber esses valores em 'class'.
#Do contrario os checkbox não são desenhados corretamente
for field_name in self.fields:
if field_name != "sinais_e_sintomas_locais" and field_name != "comorbidades_paciente":
self.fields[field_name].widget.attrs.update({
'class': 'form-control form-dinamico',
})
def clean_sinais_e_sintomas_locais(self):
import ipdb
ipdb.set_trace()
ssl = self.cleaned_data['sinais_e_sintomas_locais']
self.cleaned_data['sinais_e_sintomas_locais'] = '|'.join(ssl)
return self.cleaned_data['sinais_e_sintomas_locais']
def clean_comorbidades_paciente(self):
import ipdb
ipdb.set_trace()
cp = self.cleaned_data['comorbidades_paciente']
self.cleaned_data['comorbidades_paciente'] = '|'.join(cp)
return self.cleaned_data['comorbidades_paciente']
def save(self, *args, **kwargs):
import ipdb
ipdb.set_trace()
instance = super(EstomatologiaForm, self).save(*args, **kwargs)
instance.sinais_e_sintomas_locais = self.cleaned_data['sinais_e_sintomas_locais']
instance.comorbidades_paciente = self.cleaned_data['comorbidades_paciente']
instance.save()
return instance
models.py
...
sinais_e_sintomas_locais = models.CharField(
blank=False, choices=TIPOS_SINAIS_E_SINTOMAS, max_length=255,
verbose_name="Sinais e Sintomas locais (marque todas as opções \
válidas) *",
)
...
and here is a printscreen of the error:
The error message means: "Select a valid choice. drenagem_pus|nenhum_dos_anteriores is not one of the available choices."
Upvotes: 2
Views: 1601
Reputation: 142216
In your models - you're using...
sinais_e_sintomas_locais = models.CharField(
blank=False, choices=TIPOS_SINAIS_E_SINTOMAS, max_length=255,
verbose_name="Sinais e Sintomas locais (marque todas as opções \
válidas) *",
)
... and have choices=TIPOS_SINAIS_E_SINTOMAS
which'll work in the event of only a single selection, but where you try to pipe delimit multiple selections, they'll fail to match and cause the validation error.
Solution: remove the choices=
option. Although - you should check that all values are valid choices in your clean_<field>
methods before pipe delimiting them and saving it as a CharField
, eg:
def clean_sinais_e_sintomas_locais(self):
ssl = self.cleaned_data['sinais_e_sintomas_locais']
# Check there are no selections or only valid selections
if not (ssl or set(ssl).difference(TIPOS_SINAIS_E_SINTOMAS)):
self.cleaned_data['sinais_e_sintomas_locais'] = '|'.join(ssl)
return self.cleaned_data['sinais_e_sintomas_locais']
# Error: some individual values weren't valid...
raise forms.ValidationError('some message')
Upvotes: 1