ChoiceField or CharField in django form - django

I have a CharField in the model that needs to be selected by a ChoiceField. If the user's choice is not in the choice field then they'd select "other" and be able to type in a text input. How can I do this? I don't need the javascript; just the help with the django part.

The best approach is to have just a CharField in your models/forms with a custom widget to display your choices and 'other' with the right behavior.

RZ has a good solution
An alternative solution (with less javascript) is to have a hidden "other" CharField that is made visible when the "Other" option is selected on your ChoiceField
edit: Hidden as in style="display: none;" not a HiddenInput field
something like (with jQuery):
$("#id_myChoiceField").change(function() {
if ($(this).val() == 'other') {
$("#id_myOtherInput").show();
}
else {
$("#id_myOtherInput").hide();
}
});
You'll have to write your own validation code though and set required=False on the "Other" Charfield

Your class for that form should look something like this:
class ChoicesForm(forms.ModelForm):
# some other fields here
...
other = forms.CharField(required=False)
...
Just create a javascript that displays the 'other' text input if the user chooses 'other' among the choices.

Related

What is the django drop down type?

I Want to know:
What is the django drop down type?
if we add dropdown and add class so should we need to pass this
widgets = {
'Currency':forms.TextInput(attrs={'class':'form-control'})
}
or something?
I'M USING MODEL FORM
I NEED TO KNOW TYPE FOR EXAMPLE TEXTINPUT OR SOMETHING I WANT TO STYLE IT
Because when i pass this my dropdown convert into input i don't need like that
i just need to know what is the drop down type for example TextInput or something
QUESTION IN 1 LINE: I Want To STYLE MY CHOICE FIELD SO TO STYLE So WE NEED TO PASS SOMETHING LIKE THIS forms.TextInput so I Need To Know What is choice field type is it TextInput or something!
Any Help Will Be Appreciated!
Thanks!
ChoiceField which renders as a select html element by default.
class YourForm(forms.Form):
field = forms.ChoiceField(choices=..)
If you are using ModelForm:
class YourForm(forms.ModelForm):
field = forms.ModelChoiceField(queryset=YourModel.objects.all())
EDIT: ChoiceField use the forms.Select widget like this:
field = forms.ModelChoiceField(queryset = '', widget=forms.Select(attrs={'class':'your_class'}))
Select is the widget for choicefield.
from docs:
class ChoiceField(Field):
widget = Select
default_error_messages = {
'invalid_choice': _('Select a valid choice. %(value)s is not one of the available choices.'),
}

What Django model field do I use for a checkbox form?

I created an HTML form and am now hooking it up to Django. (I know I should have used Django to create the form, but in this case I didn't). In my models.py, I use CharField for textboxes, CharField with choices for select forms, but for checkboxes, what model field do I use? Do I have to create another class for all of the checkbox choices and then link that with a manytomany relationship? Thank you.
Probably a BooleanField:
A true/false field.
The default form widget for this field is a CheckboxInput.
If you need to accept null values then use NullBooleanField instead.
The default value of BooleanField is None when Field.default isn’t defined.
The model field reference page is a good place to find these types of answers.
I've found it helpful to think about my model rather than about HTML forms; if you choose fields based on what your model should have your forms usually work themselves out.
Possible to realize as BooleanField with default options True or False. False gives unchecked box, e.g.:
selected = models.BooleanField(default=False)
well, I don't know if you can do that in the models, but you can use it in forms read this for more information
FAVORITE_COLORS_CHOICES = (
('blue', 'Blue'),
('green', 'Green'),
('black', 'Black'),
)
class SimpleForm(forms.Form):
favorite_colors = forms.MultipleChoiceField(
required=False,
widget=forms.CheckboxSelectMultiple,
choices=FAVORITE_COLORS_CHOICES,
)

How to make a Django admin readonly textarea field

In Django admin, if I have a model field that's a TextField and set it as readonly using readonly_fields, then it's displayed as text in a <p> tag.
I'd like it to still be displayed as a textarea field, but with its disabled attribute set.
What's the simplest way to accomplish this?
use a form field
somefield = forms.CharField(
widget=forms.TextInput(attrs={'readonly':'readonly'})
)
A bit late, but here's an idea (inspired by #cinoch`s answer and this answer) that does the trick for me, with a minimum of code:
do not add the name of your TextField to the readonly_fields in your ModelAdmin subclass (otherwise step 2 has no effect)
instead, do add the following to your ModelAdmin subclass:
formfield_overrides = {
TextField: dict(widget=Textarea(attrs=dict(readonly=True)))
}
Note this requires some imports:
from django.db.models import TextField
from django.forms import Textarea
The TextField will now show up on the admin page as a scrollable Textarea instead of plain text, and its content will now be read-only, as desired.
Downside is that this applies to all TextFields in the model. If that's a problem, you should probably use a custom form as suggested by #cinoch and described in more detail here or here.
Also, this has no effect if ModelAdmin.has_change_permission() returns False.
The readonly_fields can take method names as well as field names. You could write a method that renders the value of the field in a disabled textarea.
Make sure you exclude the field from the model admin, since it will no longer be in readonly_fields.
#alasdair's answer is actually quite clever, but, unfortunately, it does not provide an example.
Here's my attempt to clarify, based on the docs for readonly_fields.
Assuming a model like so:
class MyModel(models.Model):
my_textfield = models.TextField()
The admin could look like this, using format_html to create a readonly textarea:
class MyModelAdmin(admin.ModelAdmin):
exclude = ['my_textfield']
readonly_fields = ['display_my_textfield']
#admin.display(description='my textfield')
def display_my_textfield(self, obj):
return format_html(
'<textarea cols="40" rows="10" readonly>{}</textarea>',
obj.my_textfield)
This also works if ModelAdmin.has_change_permission() returns False.

How to render django form differently based on what user selects?

I have a model and a form like this:
class MyModel(models.Model):
param = models.CharField()
param1 = models.CharField()
param2 = models.CharField()
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ('param', 'param1', 'param2')
Then I have one drop down menu with different values and based on what value is selected I'm hiding and showing fields of MyForm. Now I have to take one step further and render param2 as a CheckboxInput widget if user selects a certain value from a drop down but in other cases it should be standard text field. So how would I do that?
I know this post is almost a year old, but it took me multiple hours to even find a post related to this topic (this is the only one I found, which came up as related when submitting my own question), so I felt the need to share my solution.
I wanted to have a form that would show and require a text field if an option from a dropdown menu matched a value stored in another model. I had a foreignKey relation between two models and I passed an instance of Model1 into the ModelForm for Model2. If a value chosen for a variable in Model2 matched a variable already set in Model1, I wanted to show and require a textfield. It was basically a "choose Other and then enter your own description" scenario.
I did not want the page to reload (I was trying to have this work in both mobile and desktop browsers with the least delay/reloads and using the same code for both), so I could not use the mentioned multiple forms loading in a view option. I started trying to do it with AJAX as suggested above when I realized I was over thinking the problem.
The answer was using JS and clean methods in the form. I added a non-required field (field1) that was not in Model2 to my Model2Form. I then hid this using jQuery and only displayed it (using jQuery) if the value of another field (field2) matched the value of the variable from Model1. To make that work, I did decide to have a hidden < span > in my template with the pk of the variable so I could easily grab it with jQuery. This jQuery worked perfectly for hiding and showing the field correctly so the user could choose the "other" value and then decided to choose a different one instead (and go back and forth endlessly).
I then used a clean method in my Model2Form for field1 that raised a ValidationError if no value was entered when the value in field2 matched my Model1 variable. I accessed that variable by using "self.other = Model1.variable" in my __ init __ method and then referencing that in the clean_field1 method.
I would have liked to have been able to accomplish this without having to hide and show a field with JS, but I think the only solutions for doing so with views or ajax caused delays/reloads that I did not want. Also, I liked the general simplicity of the method I used, rather than having to figure out how to pass partial forms back and forth through the HTTPRequest.
Update:
In my situation, I was creating entries for lost and found items and if the location where the item was found was not a provided option, then I wanted to show a textbox for the user to enter the location. I created a location object that was set as the "other" location and then displayed the textbox when that object was selected as the "found" location.
In forms.py, I added an extra CharField and use a clean method to check if the field is required and then throw a ValidationError if it wasn't filled in:
class Model2Form(forms.ModelForm):
def __init__(self, Model1, *args, **kwargs):
self.other = Model1.otherLocation
super(Model2Form, self).__init__(*args, **kwargs)
...
otherLocation = forms.CharField(
label="Location Description",
max_length=255,
required=False
)
def clean_otherLocation(self):
if self.cleaned_data['locationFound'] == self.other and not self.cleaned_data['otherLocation']:
raise ValidationError("Must describe the location.")
return self.cleaned_data['otherLocation']
Then in my JavaScript, I checked if the value of the "found" location was the "other" location (the value of which I had in a hidden span on my html page). I then used .show() and .hide() on the textbox's parent element as necessary:
$("#id_locationFound").change( function(){
if ($("#id_locationFound").val() == $("#otherLocation").attr("value")){ //if matches "other" location, display textbox; otherwise, hide textbox
$("#id_otherLocation").parent().show();
}else
$("#id_otherLocation").parent().hide();
});
Your best guess would be to trigger a "POST" request when you select something from your drop down menu.
The Value of that "POST" has to correspond your values you use to determine which field you would like to output.
Now you will actually need two forms:
class MyBaseForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ('param', 'param1', 'param2')
class MyDropDownForm(MyBaseForm):
class Meta:
widgets = {
'param2': Select(attrs={...}),
}
So as you can see the DropDownForm has been derived from MyBaseForm to make sure it will have all the same properties. But we have modified the widget of one of the fields.
Now you can update your view. Please note, this is untested Python + Pseudocode
views.py
def myFormView(request):
if request.method == 'POST': # If the form has been submitted...
form = MyBaseForm(request.POST)
#submit button has not been pressed, so the dropdown has triggered the submission.
#Hence we won't safe the form, but reload it
if 'my_real_submitbotton' not in form.data:
if 'param1' == "Dropdown":
form = MyDropDownForm(request.POST)
else:
#do your normal form saving procedure
else:
form = ContactForm() # An unbound form
return render(request, 'yourTemplate.html', {
'form': form,
})
This mechanism does the following:
When the form is submitted it checks if you have pressed the "submit" button or have used a dropdown onChange to trigger a submission. My solution doesn't contain the javascript code you need to trigger the submission with an onChange. I just like to provide a way to solve it.
To use the 'my_real_submitbutton' in form.data construct you will be required to name your submit button:
<input type="submit" name="my_real_submitbutton" value="Submit" />
Of course you can choose any string as Name. :-)
In case of a submit by your dropdown field you must check which value has been selected in this drop down menu. If this value satisfies the condition you want to return a Dropdown Menu you create an instance of DropDownForm(request.POST) otherwise you can leave everything as it is and rerender your template.
On the downside this will refresh your page.
On the upside it will keep all the already entered field values. So no harm done here.
If you would like to avoid the page refresh you can keep my proposed idea but you need to render the new form via AJAX.

Django Forms: En-/Disable a Charfield dynamically

i have a form with a ChoiceField and a CharField. Now i want to enable the CharField just when i select a specific choice of the ChoiceField (e.g. choice 3). Otherwise the CharField should be disabled.
My ChoiceField
choices = (('1', 'some text',),
('2', 'some text',),
('3', 'some text',))
host = forms.ChoiceField(choices = choices)
And a simple CharField
hostAdress = forms.CharField()
Do you have any ideas to get it this way?
you can start with the char field disabled/hidden and use javascript to catch change event on the select box and change the charfield on that event. For example:
$("#id_choice").change(function(eObj) {
$("#id_char").removeAttr("disabled");
this is just an example (using jQuery), you need to make sure to disable the charfield again if the select box is unselected (not sure if you allow this behaviour) and you also need to handle the display of form errors properly if you hide the field and not enable/disable it.
I would use jQuery for this.
$('your-select-input-selector').change(function() {
var bDisable = true;
if ($(this).val() == '3'):
bDisable = !bDisabled;
$('your-text-input-selector').prop('disabled', bDisable);
});
You also need to handle the case where the select input is already set on the value 3 when you first load the page.