widgets.py

OptionalWidget

OptionalWidget - A two-component MultiField: a checkbox that indicates optional value and a field itself (widget_class = Textarea by default). The field itself is enabled / disabled according to the checkbox state via client-side $.optionalInput plugin, implemented in plugins.js:

from django_jinja_knockout.widgets import OptionalWidget

OptionalWidget(attrs={'class': 'autogrow vLargeTextField', 'cols': 40, 'rows': 2})

See also vLargeTextField usage, although it’s optional and is not the requirement for OptionalWidget.

DisplayText

DisplayText - Read-only widget for existing ModelForm bound objects. Assign to ModelForm.widgets or to ModelForm.fields.widget to make selected form fields displayed as read-only text.

Use DisplayModelMetaclass from django_jinja_knockout.forms to set all field widgets of form as DisplayText, making the whole form read-only.

In last case the form will have special renderer with table like view. See Displaying read-only “forms” for more info.

Widget allows to specify custom formatting callback to display complex fields, including foreign relationships, pre-defined string mapping for scalar True / False / None and layout override for bs_form() / bs_inline_formsets() macros. Note that it’s possible to call these macros from Django language templates like this:

{% jinja 'bs_form.htm' with _render_=1 form=form action=view_action opts=opts %}

For example, to override Member model note field DisplayText widget html output via get_text_method():

class MemberDisplayForm(WidgetInstancesMixin, RendererModelForm, metaclass=DisplayModelMetaclass):

    class Meta:

        def get_note(self, value):
            # self.instance.accepted_license.version
            if self.instance is None or self.instance.note.strip() == '':
                # Do not display empty row.
                self.skip_output = True
                return None
            return format_html_attrs(
                '<button {attrs}>Read</button>',
                attrs={
                    'class': 'component btn btn-info',
                    'data-component-class': 'Dialog',
                    'data-event': 'click',
                    'data-component-options': {
                        'title': '<b>Note for </b> <i>{}</i>'.format(self.instance.profile),
                        'message': format_html('<div class="preformatted">{}</div>', self.instance.note),
                        'method': 'alert'
                    }
                }
            )

        model = Member
        fields = '__all__'
        widgets = {
            'note': DisplayText(get_text_method=get_note)
        }

See Component IoC how to register custom Javascript data-component-class.

See DisplayText sample for the complete example.

ForeignKeyGridWidget

Implements django.admin -like widget to select the foreign key value with the optional support of in-place CRUD editing of foreign key table rows.

See ForeignKeyGridWidget section of Datatables for the detailed explanation.

Here is the screenshot of the ForeignKeyGridWidget running djk_sample project:

https://raw.githubusercontent.com/wiki/Dmitri-Sintsov/djk-sample/djk_change_or_create_foreign_key_for_inline_form.png

MultipleKeyGridWidget

django.admin -like widget to select multiple foreign key values for the form relation.

See MultipleKeyGridWidget section of Datatables for the detailed explanation.

PrefillWidget

PrefillWidget - Django form input field which supports both free text and quick filling of input text value from the list of prefilled choices. ListQuerySet has prefill_choices() method, which allows to generate lists of choices for PrefillWidget initial values like this:

from django_jinja_knockout.widgets import PrefillWidget
from django_jinja_knockout.query import ListQuerySet

# ...

self.related_members_qs = ListQuerySet(
    Member.objects.filter(
        club__id=self.request.resolver_match.kwargs.get('club_id', None)
    )
)
if self.related_members_qs.count() > 1 and isinstance(form, MemberForm):
    # Replace standard Django CharField widget to PrefillWidget with incorporated standard field widget:
    form.fields['note'].widget = PrefillWidget(
        data_widget=form.fields['note'].widget,
        choices=self.related_members_qs.prefill_choices('note')
    )
    # Replace one more field widget to PrefillWidget:
    form.fields['name'].widget = PrefillWidget(
        data_widget=form.fields['name'].widget,
        choices=self.related_members_qs.prefill_choices('name')
    )

See djk-sample project for the sample of PrefillWidget usage with inline formsets. It is even simpler to use this widget in single ModelForm without the inline formsets.

See widget_prefill_dropdown.htm macro for the default rendering of PrefillWidget.