Using django.contrib.comments, I've defined a custom comment app. I wanted to override the text area widget so that the textbox appears smaller.
So what I created was this:
#forms.py
class CustomCommentForm(CommentForm):
#...otherstuff...
comment = forms.CharField(label=_('Comment'),
widget=forms.Textarea(attrs={'rows':4}),
max_length=COMMENT_MAX_LENGTH)
But really I don't want to have to redefine the comment field. I want to just redefine the widget that's used by the field. Ie something that it seems only ModelForms can do:
class Meta:
widgets = {
'comment': Textarea(attrs={'rows': 4}),
}
Is there a way to redefine the widget without redefining the field? Or should I just set the height using CSS?
You are correct that you can only use the widgets option for a model form's Meta class.
However you don't need to redefine the entire comment field. Instead, override the form's __init__ method and change the field's widget there.
class CustomCommentForm(CommentForm):
#...otherstuff...
def __init__(self, *args, **kwargs):
super(CustomCommentForm, self).__init__(*args, **kwargs)
self.fields['comment'].widget = forms.Textarea(attrs={'rows':4})
Related
I have a User Profile ManyToManyField that by default, renders as a multi-select. On the user's profile page, I would like to override this with a TextInput field that I can add auto-complete jquery to, but I'm having a hard time seeing where to do this in Mezzanine.
TIA,
Joel
This is a Django question more than a Mezzanine question:
Widgets are what you need to set.
You're going to need a form definition, which you didn't mention. In the form definition override the default widget section as shown below. You can add class defs and more here too.
field_name = forms.CharField(widget=forms.TextInput(attrs={'style': 'display:block;','class': 'form-control'}),required=True)
It can also be done after the declaration:
field_name.widget = forms.TextInput()
It can also be done in the init within the form class:
def __init__(self, *args, **kwargs):
self.fields['field_name'].widget = forms.TextInput()
more here:
https://docs.djangoproject.com/en/1.7/ref/forms/widgets/
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)
I want to show the model field help_text as an HTML title attribute in a form, instead of it being appended to the end of the line, as is the default.
I like all the information about a model Field being in one place (in the Model definition itself), and would therefore not like to specify a custom title for each widget. It is okay, however, if there is a way to specify that the title attribute of each of widgets should be equal to the value of help_text. Is that possible? I'm looking for something to the effect of:
widgets = {'url':TextInput(attrs={'title': help_text})}
The only other way I can think of doing this, is to make custom widgets for every single one of the built-in Widget types. Is there an easier, lazier way to achieve the same effect?
Using Javascript is also an option, but that would really only be a very far-off last resort. I'm thinking that this has to be a rather common use-case; how have you guys handled it in the past?
Model._meta.get_field('field').help_text
In your case
widgets = {'url':TextInput(attrs={'title': Model._meta.get_field('url').help_text})}
Here's another way using a class decorator.
def putHelpTextInTitle (cls):
init = cls.__init__
def __init__ (self, *args, **kwargs):
init(self, *args, **kwargs)
for field in self.fields.values():
field.widget.attrs['title'] = field.help_text
cls.__init__ = __init__
return cls
#putHelpTextInTitle
class MyForm (models.Form):
#fields here
The class decorator is adapted from here
I have a django model that I'm displaying as a form using a ModelForm. The defaults work very well for me for the most part.
However, I would like my html <input ...> tags to have one additional attribute, namely I would like to include a placeholder attribute, like the following:
<input placeholder="{{field.label}}" ... />
What is the easiest way to add this attribute to my html? As far as I can tell it appears I need to implement my own filter to output the field, but this seems like overkill when all i want to do is leave everything alone but add one additional attribute.
See the documentation
class AuthorForm(ModelForm):
class Meta:
model = Author
widgets = {
'name': TextInput(attrs={'placeholder': 'name'}),
}
You could always create your own widget that derives from TextInput and includes the placeholder attribute, and use the widgets dictionary to simply map fields to your new widget without specifying the placeholder attribute for every field.
Personally I prefer to use this method:
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
self.fields['email'].widget.attrs['placeholder'] = self.fields['email'].label or 'email#address.nl'
It required more code if you don't have __init__ yet, but you don't need to specify the widget.
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)