I'm trying to create a form consisting of a multiple select field which is used to select multiple instances of my Person model.
class MyForm(forms.Form):
choices = [(p.id, str(p)) for p in Person.objects.all()]
my_field = forms.ChoiceField(widget=forms.SelectMultiple, choices=choices)
The widget looks exactly like I want, but when I submit the form, it fails with the message
Select a valid choice. ['2', '3'] is not one of the available choices.
What am I doing wrong? When removing the widget=forms.SelectMultiple, from the third line, it works, but then it's only a single select field.
You are getting the error because ChoiceField expects a single choice.
If you want to allow multiple choices, use a MultipleChoiceField.
my_field = forms.MultipleChoiceField(choices=choices)
Note you don't have to specify the widget, as it's forms.SelectMultiple by default.
Related
I have standard Django models with ForeignKey.
Django docs:
"ForeignKey is represented by django.forms.ModelChoiceField, which is a ChoiceField whose choices are a model QuerySet."
and
"If the model field has choices set, then the form field’s widget will be set to Select, with choices coming from the model field’s choices."
Now I have dropdown menu with choices.
I don't want dropdown menu where user can see options. I want CharField(textfield or similar) where user type, but still
that must be one of the options from the database for that field. He must type a valid entry.
I tried:
class TransakcijeForm(forms.ModelForm):
model = models.Transakcije
fields = .....
labels = .....
widgets ={'subscriber':forms.TextInput()}
but I receive the message:
"Select a valid choice. That choice is not one of the available choices."
(entry is correct and it works with dropdown menu)
This is my first question here and I'm sorry if I miss the form.
The reason you are getting that error is because your form is still treating the subscriber field as a ModelChoiceField because you are only overriding what widget is rendered to html. You need to change the actual field type of your field. You can define your form like this:
from django.core.exceptions import ValidationError
class TransakcijeForm(forms.ModelForm):
subscriber = forms.CharField()
class Meta:
model = models.Transakcije
fields = ....
labels = ....
def clean_subscriber(self):
subscriber_id = self.cleaned_data['subscriber']
try:
# adjust this line to appropriately get the model object that you need
subscriber = SubscriberModel.objects.get(id=subscriber_id)
return subscriber
except:
raise ValidationError('Subscriber does not exist')
The line subscriber = forms.CharField() will change the form to treat the field as a CharField rather than a ModelChoiceField. Doing this will cause the form to return the subscriber field value as a string, so you will need to get the appropriate model object based on the value of the field. That is what the clean_subscriber(self) function is for. It needs to be named like clean_<field name>(). That function will take the string that is returned by the form, try and find the correct model object and return it if an object is found. If it finds no matching objects it will raise a ValidationError so the form doesn't submit with a bad value.
I'm trying to use two widgets (one to add custom class names, one for the choices) in one field, but not sure how.. there's no clear way specified in the official documentation to do this
widget=forms.TextInput(attrs={'class': 'select is-medium'})
widget=forms.Select
If you want a Select field with custom classes in it you just have to do the following:
widget=forms.Select(attrs={'class': 'select is-medium'})
In case you want to have two widgets in one field check Django MultiWidget.
Looking for a way to use radio buttons in the Django admin. I would like to have 3 or 4 hard coded options the user can select from and I will use that selection to know what to do with the next text field. The options never need to change. Can anyone point me in the right direction? Google is not cooperating on this one...
I'm going to assume you want this on the change page for a Foo model object. Let's call the extra field my_option.
First, you'll need to use a custom form in your FooAdmin class so you can get the extra field in there:
class FooAdmin:
...
form FooForm
fields = (..., 'my_option', ...)
...
Then, just create the form with the extra option:
class FooForm(forms.ModelForm):
class Meta:
model = Foo
my_option = ChoiceField(
label = 'Options',
choices = (
(0, 'Don\'t change anything.'),
(1, 'Do some crazy stuff.'),
(2, 'Do other stuff.'),
),
initial = 0,
widget = RadioSelect,
)
ChoiceField defaults to using a select box, which is why you also need to override the widget type in the field's constructor. You can also check out TypedChoiceField if that serves your needs better.
Finally, you'll need to handle the field somewhere. I suggest overriding the clean() method in FooForm to get the value and set values in self.cleaned_data depending on what you want the option to do.
I have a form like this:
class SearchForm(forms.Form):
genus = forms.RegexField(
regex=r'^[a-zA-Z]+$',
required=False,
)
species = forms.RegexField(
regex=r'^[a-zA-Z]+$',
required=False,
)
island_group = forms.ModelChoiceField(
required=False,
queryset=Locality.objects.values_list('islandgroup', flat=True).distinct('islandgroup'),
Now, my form fails validation on the the island_group field as I am not returning model objects. I need to return the values_list to get the distinct entries. There is a bit more to this form which is why I don't want to use a model form.
My question is: what is the best way to get my form to validate?
Any help much appreciated.
Why not override the save method: call some validation function before actual save?
I had the same problem, my solution now is to use the ChoiceField instead of the ModelChoiceField. I believe this makes sense, since we do not want the user to select model instances, but distinct attribute values throughout one table column and the same attribute might well correspond to several model instances.
class SearchForm(forms.Form):
# get the distinct attributes from one column
entries = Locality.objects.values_list('islandgroup', flat=True).distinct('islandgroup')
# change the entries to a valid format for choice field
locality_choices = [(e, e) for e in entries]
# the actual choice field
island_group = forms.ChoiceField(
required=False,
choices=locality_choices)
This way Django's inbuilt validation performs exactly what we want, i.e. checking whether a member of the set of all possible attributes from one column was selected.
I have a django form that allows a user to select multiple options:
CARDS = (
("visa", "Visa"),
("mastercard", "MasterCard"),
)
class PaymentForm(forms.ModelForm):
credit_cards = forms.MultipleChoiceField(choices=CARDS, widget=forms.CheckboxSelectMultiple)
# ... etc.
I have the form's associated model setup as:
class Payment(models.Model):
user = models.OneToOneField(User)
credit_cards = models.CharField(choices=CARDS, max_length=100)
# ... etc.
But I'm thinking that a CharField with the choices parameter can only accept a single choice because my form never validates and I get an error like:
Value u"[u'visa']" is not a valid choice.
And it sure looks like a valid choice.
I've seen that some people get this working with a ManyToManyField on the model side (which I'd expect) but building a model just for a static list of credit card types seems overkill.
So: is there a specific model field type or different form configuration I should be using to support multiple selections from a pre-defined list of options?
Thanks.
http://djangosnippets.org/snippets/1200/