How do I add a class to a custom widget? - django

I've defined the following custom widget in forms.py, which over rides the standard HTML to create a "live search" select menu (user can enter free text to search options, useful when there are many options). For this widget to work, the class="selectpicker" class must be applied. How do I apply this class at the widget level?
class LiveSelectWidget(forms.widgets.Select):
template_name = "widgets/live_select.html"
option_template_name = 'widgets/live_select_option.html'

Related

Django - Field attributes in widget context

As I am using some more exotic css framework I would like to change the behaviour of the text input (provide it with label etc. by default).
I have overridden the template in django/forms/widgets/input.html
Unfortunately the widget context is missing the field, so I cannot use field properties like help_text, label, etc in my template. Therefore I would need to override the TextInput widget.
My two options are now:
Setting my own widget class for every single field in my Form / Modelform classes
Using My custom ModelForm which iterates all the fields in __init__ and replaces the widget.
Is there any better way to override django's default text_input widget?
Does is there any other way to get field.errors and field.label into the widget
(Or is there a reason why there is no label in the widget context)?

django - Creating a radio select with select box options

I want to create a set of radio options that look like so:
The non-standard part is that selecting the first or second radio button option requires the user to further specify information from a select box.
How do I do this with a django form? Based on what I see in the docs you can pass a Choices 2-tuple with only strings as the human-readable values, I need the ability to pass a widget plus a label. I am rendering the form via django-crispy-forms in the template (i.e. all my template has is {% crispy form %}), so I would prefer a solution that doesn't require any template-side manipulation.
Thanks!
in forms.py
CHOICES = (('0', 'option1',), ('1', 'option2',), ('2', 'option3',))
class NameForm(forms.ModelForm):
options = forms.ChoiceField(initial=0, widget = forms.RadioSelect(renderer = HorizontalRadioRenderer), choices=OPTIONS)

Override ChoiceField widget in Django ModelForm without re-specifying choices

I am trying to override the default widget for a Django ChoiceField while preserving the choices generated in the model. Here is the relevant part of my model:
class UserGroup(models.Model):
icon = models.CharField(max_length=100, choices=<function call>)
And of my form:
class UserGroupForm(forms.ModelForm):
icon = models.ChoiceField(widget=IconPicker)
class Meta:
model = UserGroup
fields = [ 'icon', ]
Overriding the ChoiceField's widget like this clobbers the form.fields['icon'].choices attribute normally inherited from the model and sets it to [] because Django. If I remove the icon field definition from the form, the choices are preserved - but of course the widget defaults to a Select.
(The function which generates the choices for the model field is not accessible from the form code unfortunately.)
The best I have come up with so far for is to change the icon form field definition to
icon = ChoiceField(choices=UserGroup._meta.get_field_by_name('icon')[0].choices,
widget=IconPicker)
but this is clunky and I would rather have the choices automatically passed on as in the introspected ChoiceField behavior. (I tried subclassing ChoiceField to IconChoiceField which was identical but for a default widget of IconPicker but Django converts it back to a TypedChoiceField with the default Select widget because of this issue.)
Is there a way to override the ChoiceField's widget attribute while preserving the behavior of inheriting choices from the model?
I think the reason you are losing the choices you specified in your model i.e. "sets it to []" is not "because Django", but because you override the icon field with the line icon = models.ChoiceField(widget=IconPicker)
Please note that if you are using a modelform then it is not necessary to override the widget at init, instead the widget should be specified in the Meta class in the widgets dictionary.
class UserGroupForm(forms.ModelForm):
class Meta:
model = UserGroup
fields = [ 'icon', ]
widgets = {
'icon': IconPicker
}
As for overriding the choices you can simply do self.fields['icon'].choices = UserGroupForm.ICON_CHOICES, but I don't think you need to override choices in this instance.
Figured it out. Just needed a bit of self-reference in UserGroupForm's __init__:
def __init__(self, *args, **kwargs):
super(UserGroupForm, self).__init__(*args, **kwargs)
self.fields['icon'].widget = IconPicker(choices=self.fields['icon'].choices)

Django model inheritance data saving in both models

I am trying to use the Django admin to allow rudimentary management of page menus. I have one principal menu which I decided to extend with a sub menu to allow drop downs where necessary. Because the submenu item would have the same fields as the main menu items I though it would be a good idea to use inheritance and so the sub menu would inherit all the fields from main menu as well as having a foreign key relationship like so:
# main menu
class MainMenu(models.Model):
title = models.CharField(max_length=50)
url = models.URLField()
def __unicode__(self):
return self.title
class Meta:
verbose_name_plural = "Main Menu Items"
# submenu - for drop downs
class SubMenu(MainMenu):
main_menu = models.ForeignKey(MainMenu, related_name='+', null=True, blank=True)
class Meta:
verbose_name_plural = "Sub Menu Items"
I register the models with the admin, but when I save an item in the submenu, not only does it go into the sub menu it makes the same entry in the Main Menu. Any ides what I'm doing wrong? Do I need to somehow tell Django that I inherit the methods of MainMenu without saving to it? Any help much appreciated.
But that's how model inheritance works. SubMenu has an implicit OneToOne relationship with MainMenu, but the "inherited" fields actually belong to MainMenu.
What you could do is to define a BaseMenu abstract model - use abstract = True in the inner Meta class. Now both MainMenu and SubMenu inherit from that, but SubMenu adds its main_menu link.

Python/Django BooleanField model with RadioSelect form default to empty

I'm using a Django ModelForm where my model contains a BooleanField and the form widget associated with that BooleanField is a RadioSelect widget. I'd like the the RadioSelect widget that renders to have no options selected so the user has to explicitly make a choice, but the form validation to fail if they make no selection. Is there a way to do this?
models.py
myboolean = models.BooleanField(choices=YES_NO)
forms.py
class myModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(myModelForm, self).__init__(*args, **kwargs)
self.fields['myboolean'].widget = forms.RadioSelect(choices=YES_NO)
Your code actually does what you need. It renders the radio buttons with no options selected and generate the error message if nothing is selected.
A small note about your form code. I would do it like this:
class myModelForm(forms.ModelForm):
myboolean = forms.BooleanField(widget=forms.RadioSelect(choices=YES_NO))
class Meta:
model = MyModel
Unfortunately, this is less of a Django issue than an HTML question. The HTML specification (RFC1866) says:
At all times, exactly one of the radio buttons in a set is checked. If none of the <INPUT> elements of a set of radio buttons specifies `CHECKED', then the user agent must check the first radio button of the set initially.
However, browsers have historically ignored this and implemented radio buttons in different ways.
HTML also makes this difficult because the "checked" attribute of the <INPUT> tag doesn't take a parameter, so you can't use a customized Django widget that sets this attribute to False or No.
A possible workaround is to put in a little Javascript that runs as part of the document's onLoad event that finds all the radio buttons on the page and sets the 'checked' attribute to false (using JQuery, for example).
see this:
http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#a-full-example
I creates custom field with default widget.
Cut of my models.py:
class Order(models.Model):
...
# transport = models.CharField(choices=transport.choices,max_length=25,null=True)
transport = SelectField(choices=transport.choices,max_length=25,null=True)
...
Field definition:
from django.db import models
from django.forms import widgets
class SelectField(models.CharField):
def formfield(self, **kwargs):
if self._choices:
defaults = {'widget': widgets.RadioSelect}
defaults.update(kwargs)
return super(SelectField, self).formfield(**defaults)