How to setup the initial value in select control? - django

I'm trying to setting up a select control on a form, but not achieving the expected results. For me, the strangest thing is it working in the previous control, same type.
This is the function involved:
class ProofMSPE(CrearEvidencia):
model = VRL02
form_class = VRL02Form
def get_form(self, form_class):
form = super(ProofMSPE, self).get_form(form_class)
form.fields['miembro'].queryset = self.pipol
if self.pipol.count() == 1:
form.fields['miembro'].widget.initial = [self.pipol[0].id]
form.fields['meta'].initial = self.meta
form.fields['meta'].widget.attrs['disabled'] = True
return form
The meta's control is select and I got the expected behavior, ie automatically selects an initial value (form.fields['meta'].initial = self.meta and inthe next lines, it disabled (form.fields ['meta']. widget.attrs ['disabled'] = True). This is the output in the rendered template:
<!-- begin meta-->
<div class="row">
<div class="col s12 input-field">
<select id="id_meta" name="meta" disabled>
<option value="">---------</option>
<option value="1" selected="selected">JOCE-1</option>
<option value="2">VEL-1</option>
<option value="3">VEL-2</option>
<option value="4">VEL-3</option>
</select>
<label for="id_meta">Evidencia para la meta</label>
</div>
</div>
<!-- end ./meta -->
On the other hand, with the pipol field I'm unable to get the same result. The difference, by the way, is this field has some logic: I get a filtered list of people with same criteria and the widget is create whit this list (form.fields['miembro'].queryset = self.pipol).
So far so good, but if the queryset has only one result (if self.pipol.count () == 1 :) I want that this one to be used as inital value (form.fields ['member']. Widget.initial = [self .pipol [0] .id]), but this is not working.
This is what appears when the template is rendered:
<!-- begin pipol-->
<div class="row">
<div class="col s12 input-field">
<select id="id_miembro" name="miembro">
<option value="" selected="selected">---------</option>
<option value="2">***#***.mx</option>
</select>
<label for="id_miembro">Seleccione el usuario</label>
</div>
</div>
<!-- end ./pipol -->
Thanks for your time.

You have to set the initial value to the form.field['miembro'] and not the widget, like you did with form.fields['meta'].
def get_form(self, form_class):
form = super(ProofMSPE, self).get_form(form_class)
form.fields['miembro'].queryset = self.pipol
if self.pipol.count() == 1:
# this line here
form.fields['miembro'].initial = self.pipol[0]
form.fields['meta'].initial = self.meta
form.fields['meta'].widget.attrs['disabled'] = True
return form
Select output would be:
<select id="id_miembro" name="miembro">
<option value="">---------</option>
<option value="2" selected="selected">***#***.mx</option>
</select>

Related

How to get the value from the drop down box django? without submit button

How to get the value from the dropDown Box in Django Without Submit Button
<div class="single-shorter">
<form action="." method="GET">
<label>Sort By :</label>
<select name="val" id="val">
<option selected="selected" value="name">Name</option>
<option value="price">Price</option>
</select>
</form>
</div>
You can simple obtain it using Ajax but as mentioned in comments in dont want to use that u can use value attribute in option value and using event listner and window.loction.href we can obtain this... This is one example
<select id="foo">
<option value="">Your Dropdown</option>
<option value="http://www.google.com">x</option>
<option value="http://www.facebook.com">y</option>
</select>
<script>
document.getElementById("foo").onchange = function() {
if (this.selectedIndex!==0) {
window.location.href = this.value;
}
};
</script>
as u are using django use this and also dont want to change the value attribute
<select id="my_selection">
<option value="x" href="/link/to/somewhere">value 1</option>
<option value="y" href="/link/to/somewhere/else">value 2</option>
</select>
<script>
document.getElementById('my_selection').onchange = function() {
window.location.href = this.children[this.selectedIndex].getAttribute('href');
}
</script>

Django Select2Widget not getting styled properly with crispy forms

I'm using the django-select2 package to implement Searchable Select on a ForeignKey field.
I was successful in getting the functionality to work by following the steps mentioned in the docs but I am having trouble with the styling.
To render my form I use crispy-forms. All the other widgets get rendered properly except the Select2Widget.
As can be seen in the above image, the height and width of the form element is not dynamic like other elements.
HTML code generated:
<div class=""> <select name="current_user" data-minimum-input-length="0" data-allow-clear="true" data-placeholder=""
class="select2widget form-control django-select2" required id="id_current_user">
<option value=""></option>
<option value="">---------</option>
<option value="4" selected>Arpita</option>
</select> </div>
</div>
<div id="div_id_device_admin" class="form-group"> <label for="id_device_admin" class=" requiredField">
Device admin<span class="asteriskField">*</span> </label>
<div class=""> <select name="device_admin" data-minimum-input-length="0" data-allow-clear="true" data-placeholder=""
class="select2widget form-control django-select2" required id="id_device_admin">
<option value=""></option>
<option value="">---------</option>
<option value="4" selected>Arpita</option>
</select> </div>
</div>
This is how I set the widget in ModelForm.
def __init__(self, *args, in_org, **kwargs):
...
self.fields['current_user'].widget = Select2Widget()
self.fields['current_user'].queryset = in_org.user_set.all()
I feel this is mostly an issue with CSS styling and I am unable to figure out the issue. Any help would be greatly appreciated.
For those who are looking for a solution (though I think it's not the best),
you can fix the layout issue by passing attrs={'data-width': '100%'}
e.g.
self.fields['current_user'].widget = Select2Widget(attrs={'data-width': '100%'})
or
current_user = forms.ChoiceField(
widget=ModelSelect2Widget(
model=User,
search_fields=['username__istartswith'],
attrs={'data-width': '100%'},
),
)

How to dynamically set the default selected option in a Jinja template?

I am building a dashboard which will have some information about users. I am trying to set value to select tag using Django but the value never get assigned. Here is my code.
My model look something like this
class User(models.Model):
first_name
last_name
reg_status
I need to fill in the template with the reg_status. The reg_status can contain three options, they are as mentioned below:
mailed
register
not register
The value of reg_status is dynamic. For example, if I pass in reg_status = mailed from my view, I need the <option value='mailed'> to be selected. However, if I pass in the reg_status = register from my view, I need the <option value='register'> to be selected.
Here is how I am trying to render the content in the template:
{% for u in user %}
<input type='text' value={{u.first_name}}/>
<input type='text' value={{u.last_name}}/>
<select value={{u.reg_status}>
<option value='mailed'>mailed</option>
<option value='register'>register</option>
<option value='not register'>not register</option>
</select>
{% endfor %}
The output give 'mailed' as selected for all instance even if the value is set to 'registered' or 'not registered'.
You can use a Jinja ternary operator. It's a little greedy because you're doing the same operation 3 times. You could also look into setting a global variable with Jinja (see the documentation, scroll down to Scoping Behavior).
<select value='{{ u.reg_status }}'>
<option value='mailed' {{ "selected='selected'" if u.reg_status == 'mailed' else "" }}>mailed</option>
<option value='register' {{ "selected='selected'" if u.reg_status == 'register' else "" }}>register</option>
<option value='not register' {{ "selected='selected'" if u.reg_status == 'not register' else "" }}>not register</option>
</select>

How to display a tree in select2?

I have a Categories tree (MP_Node). It is necessary to display them in the form of a tree at the select2.
models.py
class Category(MP_Node):
....
forms.py
class ProductCreateForm(forms.ModelForm):
class Meta:
model = Product
fields = (
...., 'category', ....
)
def __init__(self, *args, **kwargs):
super(ProductCreateForm, self).__init__(*args, **kwargs)
self.fields['category'].empty_label = None
self.fields['category'] = ModelChoiceField(queryset=Category.objects.all(), widget=forms.Select(
attrs={'class': 'select2', 'style': 'width: 165px'}))
html
<div class="field inline select">
<label for="id_category" class="subhead">Категория:</label>
<select name="category" style="width: 165px" required="" class="select2 select2-hidden-accessible" id="id_category" tabindex="-1" aria-hidden="true">
<option value="" selected="">---------</option>
<option value="1">Food</option>
<option value="4">Meal</option>
<option value="2">Sweet</option>
<option value="3">Milk</option>
<option value="9">Sport</option>
<option value="6">Football</option>
<option value="7">Ball</option>
<option value="5">Form</option>
<option value="8">Shirt</option>
<option value="10">T-Shirt</option>
<option value="11">Attribute</option>
</select>
<span class="select2 select2-container select2-container--default select2-container--focus" dir="ltr" style="width: 165px;"><span class="selection"><span class="select2-selection select2-selection--single" role="combobox" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-labelledby="select2-id_category-container"><span class="select2-selection__rendered" id="select2-id_category-container"><span class="select2-selection__placeholder"> </span></span><span class="select2-selection__arrow" role="presentation"><b role="presentation"></b></span></span></span><span class="dropdown-wrapper" aria-hidden="true"></span></span>
</div>
I get select
Food
Meal
Sweet
Milk
Sport
Football
Ball
Form
Shirt
T-Shirt
Attribute
Need to receive
Food
Meal
Sweet
Milk
Sport
Football
Ball
Form
Shirt
T-Shirt
Attribute
js
$('select').select2({
placeholder: " ",
minimumResultsForSearch: Infinity
});
Was looking for the same thing.
Found this: https://github.com/clivezhg/select2-to-tree
Compat: Select2 4+
Also looked at this, but did not use:
https://github.com/maliming/select2-treeview
Use django-select2 to display tree struture effectively

Customizing Django forms with RadioSelect widget

So I'm using jQuery UI to skin the radio buttons but I can't get Django to render my form the way it has to be done.
I need to have this structure:
<table>
<tr>
<td><label for="notify_new_friends">Notify when new friends join</label></td>
<td class="radio">
<input type="radio" name="notify_new_friends" id="notify_new_friends_immediately" value="1" checked="checked"/><label for="notify_new_friends_immediately">Immediately</label>
<input type="radio" name="notify_new_friends" id="notify_new_friends_never" value="0"/><label for="notify_new_friends_never">Never</label>
</td>
</tr>
</table>
So to summarize that I need the radio buttons within a class (radio) where they have an input and a label for.
When I render the form in my template with {{ profile_form.notify_new_friends }} I get the following:
<ul>
<li><label for="id_notify_new_friends_0"><input type="radio" id="id_notify_new_friends_0" value="0" name="notify_new_friends" /> Immediately</label></li>
<li><label for="id_notify_new_friends_1"><input type="radio" id="id_notify_new_friends_1" value="1" name="notify_new_friends" /> Never</label></li>
</ul>
Which is exactly what I want except for the list-part. So I tried looping over it which gives me the labels formatted differently:
{% for item in profile_form.notify_new_friends %}
{{ item }}
{% endfor %}
which gives me:
<label><input type="radio" name="notify_new_friends" value="0" /> Immediately</label>
<label><input type="radio" name="notify_new_friends" value="1" /> Never</label>
So the problem here is that it stops using label for and starts using just label to wrapp it all with.
I also tried doing something like this, but then the label and label_tag don't render anything.
{{ profile_form.notify_new_friends.0 }}
{{ profile_form.notify_new_friends.0.label_tag }}
{{ profile_form.notify_new_friends.0.label }}
So does anyone know how I can render this properly!?
FYI, this is my forms.py:
self.fields['notify_new_friends'] = forms.ChoiceField(label='Notify when new friends join', widget=forms.RadioSelect, choices=NOTIFICATION_CHOICES)
In my code I discovered that changing the widget from
forms.RadioSelect
to
forms.RadioSelect(attrs={'id': 'value'})
magically causes the resulting tag value to include the id attribute with the index of the item appended. If you use
{% for radio in form.foo %}
<li>
{{ radio }}
</li>
{% endfor %}
in the form you get a label wrapped around an input. If you want the more conventional input followed by label, you need to do this:
{% for radio in form.value %}
<li>
{{ radio.tag }}
<label for="value_{{ forloop.counter0 }}">{{ radio.choice_label }}</label>
</li>
{% endfor %}
Unfortunately this is more complicated than it should be, it seems you need to override at least 2 classes: RadioRenderer and RadioInput. The following should help you get started but you might need to tweak it a little.
First create a custom radio button input widget. The only purpose of us overriding the render method is to get rid of annoying structure Django enforces (<label><input /></label>) where instead we want ours (<label /><input />):
class CustomRadioInput(RadioInput):
def render(self, name=None, value=None, attrs=None, choices=()):
name = name or self.name
value = value or self.value
attrs = attrs or self.attrs
if 'id' in self.attrs:
label_for = ' for="%s_%s"' % (self.attrs['id'], self.index)
else:
label_for = ''
choice_label = conditional_escape(force_unicode(self.choice_label))
return mark_safe(u'%s<label%s>%s</label>' % (self.tag(), label_for, choice_label))
Now we need to override RadioRenderer in order to:
Force it to use our custom radio input widget
Remove <li> wraping every single input field and <ul> wrapping all input fields:
Something along these lines should do:
class RadioCustomRenderer(RadioFieldRenderer):
def __iter__(self):
for i, choice in enumerate(self.choices):
yield CustomRadioInput(self.name, self.value, self.attrs.copy(), choice, i)
def __getitem__(self, idx):
choice = self.choices[idx]
return CustomRadioInput(self.name, self.value, self.attrs.copy(), choice, idx)
def render(self):
return mark_safe(u'%s' % u'\n'.join([u'%s' % force_unicode(w) for w in self]))
Finally instruct Django to use custom renderer
notify_new_friends = forms.ChoiceField(label='Notify when new friends join', widget=forms.RadioSelect(renderer=RadioCustomRenderer), choices=NOTIFICATION_CHOICES)
Please bear in mind: This now outputs radio buttons together with encompassing <td> hence you need to build a table around it in your template, something along these lines:
<table>
<tr>
<td><label for="{{field.auto_id}}">{{field.label}}</label></td>
<td>{{ field.errors }} {{field}}</td>
</tr>
</table>
If anyone stumble upon this problem and just want to render the radio button without ul: they should follow this link.
https://docs.djangoproject.com/en/3.1/ref/forms/widgets/#selector-widgets
Example below.
{% for radio in myform.beatles %}
<div class="myradio">
{{ radio }}
</div>
{% endfor %}
Since it doesn't seem to be a good way to do this I chose to rearrange the generated code using jQuery.
// First remove the ul and li tags
$('.radio ul').contents().unwrap();
$('.radio li').contents().unwrap();
// Then move the input to outside of the label
$('.radio > label > input').each(function() {
$(this).parent().before(this);
});
// Then apply the jQuery UI buttonset
$( ".radio" ).buttonset();
This made it go from:
<ul>
<li><label for="id_notify_new_friends_0"><input type="radio" id="id_notify_new_friends_0" value="0" name="notify_new_friends" /> Immediately</label></li>
<li><label for="id_notify_new_friends_1"><input type="radio" id="id_notify_new_friends_1" value="1" name="notify_new_friends" /> Never</label></li>
</ul>
to:
<input type="radio" id="id_notify_new_friends_0" value="0" name="notify_new_friends" /><label for="id_notify_new_friends_0"> Immediately</label></li>
<input type="radio" id="id_notify_new_friends_1" value="1" name="notify_new_friends" /><label for="id_notify_new_friends_1"> Never</label></li>
and my jQuery UI styling works fine.
Try like this , I got it..
from django.forms.widgets import RadioFieldRenderer
from django.utils.encoding import force_unicode
from django.utils.safestring import mark_safe
class RadioCustomRenderer( RadioFieldRenderer ):
def render( self ):
return mark_safe(u'%s' % u'\n'.join([u'%s' % force_unicode(w) for w in self]))
in form
widgets = {
'validity': forms.RadioSelect(renderer=RadioCustomRenderer),
}