Reputation: 649
Suppose you have a certain model
class MyModel(models.Model):
Name = models.CharField(max_length=64)
And an accompaniying form you use for creation
class CreateMyModelForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['name']
In a normal situation, when the form is rendered in a template I usually loop over the fields in the template
{%for field in form%}
{{field}}
{%endfor%}
When custom styling is needed, I usually have to resort to placing my <div>
s and <span>
s in that loop, and specify the base widget and its attrs
in the Meta
subclass.
Looking through the Django Documentation on the topic, I understand that it seems like I have to play with the Media
subclass to make all the manipulation happen in the widgets
property in the Meta
, but I just can't wrap my head around it.
Suppose I have a template where TextInput
forms need to render as in this template:
<div class="form-group input-group">
<span class="input-group-addon">Name</span>
<input type="text" name="name" class="form-control" placeholder="MyModel Name">
</div>
How do I go about creating a widget so that I can get the same result by using:
class CreateMyModelForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['name']
widgets={'name':MyWidget(addon="Name",placeholder="MyModel Name")}
I understand that the placeholder is something I can put in the attrs
initialization of TextInput
, but the addon (or parent div, in this case) is not or at least not to my knowledge
I apologize for a long question, I just felt that I need to thoroughly explain this problem because it's been bothering me for a while...
Upvotes: 4
Views: 7600
Reputation: 11665
We can do like below.
from django import forms
from django.template import loader
from django.utils.safestring import mark_safe
class MyWidget(forms.Widget):
template_name = 'widget_template.html'
def get_context(self, name, value, attrs=None):
return {'widget': {
'name': name,
'value': value,
}}
def render(self, name, value, attrs=None):
context = self.get_context(name, value, attrs)
template = loader.get_template(self.template_name).render(context)
return mark_safe(template)
<div class="form-group input-group">
<span class="input-group-addon">Name</span>
<input type="text" class="form-control" id="mywidget-{{ widget.name }}" name="{{ widget.name }}" />
</div>
Upvotes: 10