I have been able to get the BooleanField from my main Feature class to be rendered as a radiobutton for its form, but when viewed, the form doesn't have the corresponding value preselected. How do I get it to select the appropriate one, given a boolean value? Thanks
models.py:
class Feature(models.Model):
for_biz = models.BooleanField()
class FeatureForm(ModelForm):
choices = ( (1,'Business'), (0, 'Customers') )
for_biz = forms.TypedChoiceField(
coerce=lambda x: bool(int(x)),
choices=choices,
widget=forms.RadioSelect,
)
class Meta:
model = Feature
fields = (
'for_biz',
)
views.py:
def edit_feature(request, f_id):
f = get_object_or_404(Feature, id=f_id)
form = FeatureForm(instance=f)
....
Make it a PositiveSmallIntegerField with choices. BooleanField doesn't really buy you anything, and as you already saw it only gives you more trouble to deal with.
Related
I want to try populating fields from the database in Django form, but it's showing me blankly.
Can anyone give me an idea?
Here I am sharing my code.
class circleform(forms.ModelForm):
class Meta:
model = curd
fields = ['Zone','Circle','circle_code','circle_address']
widgets = {
'Zone':forms.Select(attrs = {'class':'form-control'}),
'Circle':forms.TextInput(attrs = {'class':'form-control'}),
'circle_code':forms.TextInput(attrs = {'class':'form-control'}),
'circle_address':forms.TextInput(attrs = {'class':'form-control'}),
}
I think you could use a field overriding like
class YourForm(forms.ModelForm):
your_foreign_key_field_name = forms.ModelChoiceField(queryset=YourChoiceModel.objects.all())
class Meta:
....
or in case you just want a form that reflect all your model's fields, try using Admin
https://docs.djangoproject.com/en/4.1/intro/tutorial07/
If you are looking for a field that will populate your query based on a query then ModelChoiceField is what you are looking for. You can use it like that
class circleform(forms.ModelForm):
your_field = ModelChoiceField(queryset="you query here to populate choice field")
# ...
but if you have some hard-coded choices that you want to populate then you can pass a choices=YOUR_CHOICES_TUPLE like that.
class circleform(forms.ModelForm):
class Meta:
model = curd
fields = ['Zone','Circle','circle_code','circle_address']
YOUR_CHOICES = (
('', 'Select your zone'),
('1', 'First'), #First one is the value of the select option and the second is the displayed value in the option
('2', 'second'),
)
widgets = {
'Zone':forms.Select(attrs = {'class':'form-control'}, choices=YOUR_CHOICES), # new
}
I have a simple model in django with a field using choices. As it is now, I am forced to use one of the available choices, how can I be able to use those choices and also be able to enter text manually?
WHERE_CHOICES = (
('CHL', 'Center HL'),
('CHD', 'Center HD')
)
class Event(models.Model):
ev_start = models.DateTimeField()
ev_end = models.DateTimeField()
where = models.CharField(max_length=3, default='CHL', choices=WHERE_CHOICES)
Thanks
You can override the admin form field widget with a datalist tag.
It would look like that (using the floppyforms library):
class EventAdminForm(ModelForm):
class Meta:
model = Event
fields = "__all__"
widgets = {
'where': floppyforms.widgets.Input(datalist=[v[0] for v in Event.WHERE_CHOICES])
}
class EventAdmin(admin.ModelAdmin):
form = EventAdminForm
admin.site.register(Event, EventAdmin)
My goal is to be able to use get_FOO_display(), and so as far as I understand I will have to have choices specified in the model field. At the same time I am wanting to render the form using a ModelForm as a RadioButton.
The problem I am having is that the default value of "------" that would be used in a dropdown select is showing up as one of my RadioButton options.
models.py
class Medication(models.Model):
YESNO_CHOICES = [(0, 'No'), (1, 'Yes')]
Allergies = models.BigIntegerField(verbose_name='Allergies:', choices=YESNO_CHOICES)
forms.py
I have tried just specifying a RadioButton widget in the ModelForm.
class mfMedication(ModelForm):
class Meta:
model = Medication
widgets = {
'Allergies': RadioSelect(),
}
and also specifying the RadioButton with the CHOICES.
class mfMedication(ModelForm):
class Meta:
model = Medication
widgets = {
'Allergies': RadioSelect(choices=Medication.YESNO_CHOICES),
}
In both cases I get three radiobuttons:
"": -------
0 : No
1 : Yes
The only way I do not get the "-------" is to remove choices=YESNO_CHOICES from my model field, but this stops get_FOO_display() from working.
Any approach that you have used to get this working would be greatly appreciated.
Thanks. JD.
If you want to prevent displaying of ------- choice, you should specify empty_label=None in your form field.
Also, I recomend you to use BooleanField for model and TypedChoiceField for form:
models.py:
class Medication(models.Model):
Allergies = models.BooleanField('Allergies:')
forms.py:
class MedicationForm(forms.ModelForm):
YESNO_CHOICES = ((0, 'No'), (1, 'Yes'))
Allergies = forms.TypedChoiceField(
choices=YESNO_CHOICES, widget=forms.RadioSelect, coerce=int
)
Using the BigIntegerField, you can also set the default=0 or whatever choice you would like it to be.
How can I remove "------" from rendered choices?
I use in my model form:
widgets = {
'event_form': forms.CheckboxSelectMultiple(),
}
In model I have IntegerField with choices:
EVENT_FORM_CHOICES = (
(1, _(u'aaaa')),
(2, _(u'bbbb')),
(3, _(cccc')),
(4, _(u'dddd')),
(5, _(eeee'))
)
rendered choices contain --------- as first possible choice. How I can get rid of it?
EDIT:
The only working way i figured out is (in init method):
tmp_choices = self.fields['event_form'].choices
del tmp_choices[0]
self.fields['event_form'].choices = tmp_choices
but it's not very elegant way :)
Update
a similar example maybe useful:
country = ModelChoiceField(reference_class = Country, choices= country_choices,
required=True, empty_label=None, widget=forms.Select)
If you want a solution client side instead:
<script>
$("#selectBox option[value='-----']").remove();
</script>
Django is including the blank choice because the field doesn't have a default value.
If you set a default value in your model, then Django will not include the blank choice.
class MyModel(models.Model):
event_form = models.PositiveSmallIntegerField(choices=EVENT_FORM_CHOICES, default=1)
If you don't want to set a default value in your model, then you can explicitly declare the field and choices in the model form, or change the choices in the model form's __init__ method.
I ran into a similar problem but fixed it this way. First, download and install https://pypi.python.org/pypi/django-multiselectfield. If you don't know how to install, look here: django-multiselectfield can't install. Then, in models.py:
from multiselectfield import MultiSelectField
CHOICES_FOR_ITEM_WITH_CHOICES = (
("choice 1", "choice 1"),
("choice 2", "choice 2"),
("choice 3", "choice 3"),
)
class MyModel(models.Model):
item_with_choices = MultiSelectField(max_length=MAX_LENGTH, null=True, blank=True)
In admin.py:
from .forms import MyModelForm
class MyModelAdmin(admin.ModelAdmin):
form = MyModelForm
list_display = ('item_with_choices',)
list_filter = ('item_with_choices',)
search_fields = ('item_with_choices',)
admin.site.register(MyModel, MyModelAdmin)
In forms.py (you can name this whatever you like):
from .models import MyModel
class MyModelForm(ModelForm):
class Meta:
model = MyModel
fields = (
'item_with_choices',
)
def clean(self):
# do something that validates your data
return self.cleaned_data
This builds off the answer here: Django Model MultipleChoice
I need to make a form, which have 1 select and 1 text input. Select must be taken from database.
model looks like this:
class Province(models.Model):
name = models.CharField(max_length=30)
slug = models.SlugField(max_length=30)
def __unicode__(self):
return self.name
It's rows to this are added only by admin, but all users can see it in forms.
I want to make a ModelForm from that. I made something like this:
class ProvinceForm(ModelForm):
class Meta:
CHOICES = Province.objects.all()
model = Province
fields = ('name',)
widgets = {
'name': Select(choices=CHOICES),
}
but it doesn't work. The select tag is not displayed in html. What did I wrong?
UPDATE:
This solution works as I wanto it to work:
class ProvinceForm(ModelForm):
def __init__(self, *args, **kwargs):
super(ProvinceForm, self).__init__(*args, **kwargs)
user_provinces = UserProvince.objects.select_related().filter(user__exact=self.instance.id).values_list('province')
self.fields['name'].queryset = Province.objects.exclude(id__in=user_provinces).only('id', 'name')
name = forms.ModelChoiceField(queryset=None, empty_label=None)
class Meta:
model = Province
fields = ('name',)
Read Maersu's answer for the method that just "works".
If you want to customize, know that choices takes a list of tuples, ie (('val','display_val'), (...), ...)
Choices doc:
An iterable (e.g., a list or tuple) of
2-tuples to use as choices for this
field.
from django.forms.widgets import Select
class ProvinceForm(ModelForm):
class Meta:
CHOICES = Province.objects.all()
model = Province
fields = ('name',)
widgets = {
'name': Select(choices=( (x.id, x.name) for x in CHOICES )),
}
ModelForm covers all your needs (Also check the Conversion List)
Model:
class UserProvince(models.Model):
user = models.ForeignKey(User)
province = models.ForeignKey(Province)
Form:
class ProvinceForm(ModelForm):
class Meta:
model = UserProvince
fields = ('province',)
View:
if request.POST:
form = ProvinceForm(request.POST)
if form.is_valid():
obj = form.save(commit=True)
obj.user = request.user
obj.save()
else:
form = ProvinceForm()
If you need to use a query for your choices then you'll need to overwrite the __init__ method of your form.
Your first guess would probably be to save it as a variable before your list of fields but you shouldn't do that since you want your queries to be updated every time the form is accessed. You see, once you run the server the choices are generated and won't change until your next server restart. This means your query will be executed only once and forever hold your peace.
# Don't do this
class MyForm(forms.Form):
# Making the query
MYQUERY = User.objects.values_list('id', 'last_name')
myfield = forms.ChoiceField(choices=(*MYQUERY,))
class Meta:
fields = ('myfield',)
The solution here is to make use of the __init__ method which is called on every form load. This way the result of your query will always be updated.
# Do this instead
class MyForm(forms.Form):
class Meta:
fields = ('myfield',)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Make the query here
MYQUERY = User.objects.values_list('id', 'last_name')
self.fields['myfield'] = forms.ChoiceField(choices=(*MYQUERY,))
Querying your database can be heavy if you have a lot of users so in the future I suggest some caching might be useful.
the two solutions given by maersu and Yuji 'Tomita' Tomita perfectly works, but there are cases when one cannot use ModelForm (django3 link), ie the form needs sources from several models / is a subclass of a ModelForm class and one want to add an extra field with choices from another model, etc.
ChoiceField is to my point of view a more generic way to answer the need.
The example below provides two choice fields from two models and a blank choice for each :
class MixedForm(forms.Form):
speaker = forms.ChoiceField(choices=([['','-'*10]]+[[x.id, x.__str__()] for x in Speakers.objects.all()]))
event = forms.ChoiceField(choices=( [['','-'*10]]+[[x.id, x.__str__()] for x in Events.objects.all()]))
If one does not need a blank field, or one does not need to use a function for the choice label but the model fields or a property it can be a bit more elegant, as eugene suggested :
class MixedForm(forms.Form):
speaker = forms.ChoiceField(choices=((x.id, x.__str__()) for x in Speakers.objects.all()))
event = forms.ChoiceField(choices=(Events.objects.values_list('id', 'name')))
using values_list() and a blank field :
event = forms.ChoiceField(choices=([['','-------------']] + list(Events.objects.values_list('id', 'name'))))
as a subclass of a ModelForm, using the one of the robos85 question :
class MixedForm(ProvinceForm):
speaker = ...