I am having a difficult time finding documentation on how to write a custom widget.
My questions are:
Thanks.
A widget is Django's representation of an HTML input element. The widget handles the rendering of the HTML, and the extraction of data from a GET/POST dictionary that corresponds to the widget. The HTML generated by the built-in widgets uses HTML5 syntax, targeting <!
In the Form Builder, click the Add Form Element button. Go to the Widgets tab, then search for the widget you'd like to use. Click the widget to add. You can also drag and drop it anywhere to your form.
Form widgets allows users to input data and provides them interaction capability with the application. Every Form widget inherits properties from Widget class which in turn inherits properties from UIObject and Wigdet classes.
You're right in that Django doesn't supply documentation on this specific topic. I advise you to look at the builtin widgets in django.forms.widgets
(I'll reference classes from that module below).
If I build a custom widget, can it be used equivalently for the admin interface or for normal forms?
Admin overrides some widgets (see django.contrib.admin.options.FORMFIELD_FOR_DBFIELD_DEFAULTS
). You can probably subclass ModelAdmin
and change the formfield_overrides
attribute, but I have never done anything with ModelAdmin
so I can't help here...
If I want to allow the user to edit a list of items, what widget should I subclass? What methods of the widget do I need to override/implement?
Your widget probably doesn't have anything in common with the default widgets (with Select
if any?!). Subclass from Widget
and if you find any common pattern with builtins, you can still change it later.
Implement the following methods:
render(self, name, value, attrs=None, renderer=None)
Check out Input.render
for a simple example. It also supports user-defined attributes that are included in the HTML. You may also want to add "id" attributes, see MultipleHiddenInput.render
on how to do that. Don't forget to use mark_safe
when outputting HTML directly. If you have a rather complex widget you can use template rendering (example).
_has_changed(self, initial, data)
Optional. Used in admin to log messages about what was changed.
What widget method is responsible for going from the user's input back to the data model?
That has nothing to do with the widget - Django can't know what widget was used in an earlier request. It can only use the form (POST) data sent from the form. Therefore, the field method Field.to_python
is used to convert input to the Python data type (may raise ValidationError
if the input is invalid).
Additionally to the other answers, this is a small code sample of a custom widget:
widgets.py
:
from django.forms.widgets import Widget from django.template import loader from django.utils.safestring import mark_safe class MyWidget(Widget): template_name = 'myapp/my_widget.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)
my_widget.html
:
<textarea id="mywidget-{{ widget.name }}" name="{{ widget.name }}"> {% if widget.value %}{{ widget.value }}{% endif %}</textarea>
Widgets are now rendered using the form rendering API.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With