Пример #1
0
    def _render_field(self, field: BoundField, attrs: TypeAttrs = None) -> str:

        attrs = attrs or self._attrs_get_basic(self.attrs, field)

        placeholder = attrs.get('placeholder')

        if placeholder is None:

            if self.opt_placeholder_label:
                attrs['placeholder'] = field.label

            elif self.opt_placeholder_help:
                attrs['placeholder'] = field.help_text

        title = attrs.get('title')

        if title is None:

            title_label = self.opt_title_label
            title_help = self.opt_title_help

            if title_label or title_help:

                if title_label:
                    attrs['title'] = field.label

                elif title_help:
                    attrs['title'] = field.help_text

        out = field.as_widget(attrs=attrs)

        if field.field.show_hidden_initial:
            out += field.as_hidden(only_initial=True)

        return f'{out}'
Пример #2
0
def get_field_options(context: Context, field: BoundField) -> str:
    """
    Retrieves the field options for a multiple choice field, and stores it in the context.

    This tag exists because we can't call functions within Django templates directly, and is
    only made use of in the template for ModelChoice (and derived) fields - but would work fine
    with anything that makes use of your standard `<select>` element widgets.

    This stores the parsed options under `options` in the context, which will subsequently
    be available in the template.

    Usage:

    ```django
    {% get_field_options field_object %}

    {% if options %}
      {% for group_name, group_choices, group_index in options %}
        ...
      {% endfor %}
    {% endif %}
    ```
    """
    widget = field.field.widget

    if field.value() is None:
        value: List[str] = []
    else:
        value = [str(field.value())]

    context["options"] = widget.optgroups(field.name, value)
    return ""
Пример #3
0
    def get_bound_field(self, form, field_name):
        bound_field = BoundField(form, self, field_name)

        # Override initial() to allow passing multiple values
        bound_field.initial = self._get_initial_value(form.initial, field_name)

        # Modify the QuerySet of the field before we return it. Limit choices to any data already bound: Options
        # will be populated on-demand via the APISelect widget.
        data = bound_field.value()
        if data:
            filter = self.filter(field_name=self.to_field_name or 'pk',
                                 queryset=self.queryset)
            self.queryset = filter.filter(self.queryset, data)
        else:
            self.queryset = self.queryset.none()

        # Set the data URL on the APISelect widget (if not already set)
        widget = bound_field.field.widget
        if not widget.attrs.get('data-url'):
            app_label = self.queryset.model._meta.app_label
            model_name = self.queryset.model._meta.model_name
            data_url = reverse('{}-api:{}-list'.format(app_label, model_name))
            widget.attrs['data-url'] = data_url

        return bound_field
Пример #4
0
    def get_bound_field(self, form, field_name):
        bound_field = BoundField(form, self, field_name)

        # Modify the QuerySet of the field before we return it. Limit choices to any data already bound: Options
        # will be populated on-demand via the APISelect widget.
        data = bound_field.value()
        if data:
            field_name = getattr(self, 'to_field_name') or 'pk'
            filter = self.filter(field_name=field_name)
            try:
                self.queryset = filter.filter(self.queryset, data)
            except TypeError:
                # Catch any error caused by invalid initial data passed from the user
                self.queryset = self.queryset.none()
        else:
            self.queryset = self.queryset.none()

        # Set the data URL on the APISelect widget (if not already set)
        widget = bound_field.field.widget
        if not widget.attrs.get('data-url'):
            app_label = self.queryset.model._meta.app_label
            model_name = self.queryset.model._meta.model_name
            data_url = reverse('{}-api:{}-list'.format(app_label, model_name))
            widget.attrs['data-url'] = data_url

        return bound_field
Пример #5
0
    def _html_output(self, normal_row, error_row, row_ender, help_text_html, errors_on_separate_row):
        # Customized to handle special case for reCaptcha forms (not rendering remote_ip field)
        "Helper function for outputting HTML. Used by as_table(), as_ul(), as_p()."
        top_errors = self.non_field_errors() # Errors that should be displayed above all fields.
        output, hidden_fields = [], []

        for name, field in self.fields.items():
            html_class_attr = ''
            bf = BoundField(self, field, name)
            bf_errors = self.error_class([conditional_escape(error) for error in bf.errors]) # Escape and cache in local variable.
            if not bf.is_hidden:
                # Create a 'class="..."' atribute if the row should have any
                # CSS classes applied.
                css_classes = bf.css_classes()
                if css_classes:
                    html_class_attr = ' class="%s"' % css_classes

                if errors_on_separate_row and bf_errors:
                    output.append(error_row % force_unicode(bf_errors))

                if bf.label:
                    label = conditional_escape(force_unicode(bf.label))
                    # Only add the suffix if the label does not end in
                    # punctuation.
                    if self.label_suffix:
                        if label[-1] not in ':?.!':
                            label += self.label_suffix
                    label = bf.label_tag(label) or ''
                else:
                    label = ''

                if field.help_text:
                    help_text = help_text_html % force_unicode(field.help_text)
                else:
                    help_text = u''

                output.append(normal_row % {
                    'errors': force_unicode(bf_errors),
                    'label': force_unicode(label),
                    'field': unicode(bf),
                    'help_text': help_text,
                    'html_class_attr': html_class_attr
                })

        if top_errors:
            output.insert(0, error_row % force_unicode(top_errors))

        return mark_safe(u'\n'.join(output))
Пример #6
0
    def test_get_field_options_value(self):
        unbound_field = ChoiceField()
        field = BoundField(Form(initial={"field": "Value"}), unbound_field,
                           "field")

        context = Context({"field": field})
        self.TEMPLATE.render(context)
Пример #7
0
 def _convert_to_bound_fields(form, i18n_field_names):
     bound_fields = []
     for field_name in i18n_field_names:
         local_fields = field_mapping[field_name]
         for local_name in local_fields:
             local_field = form_instance.fields[local_name]
             bound_field = BoundField(form, local_field, local_name)
             bound_fields.append(bound_field)
     return bound_fields
Пример #8
0
 def _render_label(self, field: BoundField) -> str:
     label = field.label_tag(
         attrs=self._attrs_get_basic(self.attrs_labels, field),
         label_suffix=(
             # Get rid of colons entirely.
             '' if not self.opt_label_colon else (
                 # Or deduce...
                 '' if isinstance(field.field.widget, CheckboxInput) else
                 None)))
     return f'{label}'
Пример #9
0
    def get_bound_field(self, form, field_name):
        bound_field = BoundField(form, self, field_name)

        # Modify the QuerySet of the field before we return it. Limit choices to any data already bound: Options
        # will be populated on-demand via the APISelect widget.
        data = self.prepare_value(bound_field.data or bound_field.initial)
        if data:
            filter = self.filter(field_name=self.to_field_name or 'pk', queryset=self.queryset)
            self.queryset = filter.filter(self.queryset, data)
        else:
            self.queryset = self.queryset.none()

        return bound_field
Пример #10
0
    def get_bound_field(self, form, field_name):
        bound_field = BoundField(form, self, field_name)

        # Modify the QuerySet of the field before we return it. Limit choices to any data already bound: Options
        # will be populated on-demand via the APISelect widget.
        field_name = '{}{}'.format(self.to_field_name or 'pk', self.field_modifier)
        if bound_field.data:
            self.queryset = self.queryset.filter(**{field_name: self.prepare_value(bound_field.data)})
        elif bound_field.initial:
            self.queryset = self.queryset.filter(**{field_name: self.prepare_value(bound_field.initial)})
        else:
            self.queryset = self.queryset.none()

        return bound_field
Пример #11
0
    def get_bound_field(self, form, field_name):
        bound_field = BoundField(form, self, field_name)

        # Set the initial value based on prescribed child fields (if not set)
        if not self.initial and self.initial_params:
            filter_kwargs = {}
            for kwarg, child_field in self.initial_params.items():
                value = form.initial.get(child_field.lstrip("$"))
                if value:
                    filter_kwargs[kwarg] = value
            if filter_kwargs:
                self.initial = self.queryset.filter(**filter_kwargs).first()

        # Modify the QuerySet of the field before we return it. Limit choices to any
        # data already bound: Options will be populated on-demand via the APISelect
        # widget
        data = bound_field.value()
        if data:
            field_name = getattr(self, "to_field_name") or "pk"
            filter = self.filter(field_name=field_name)
            try:
                self.queryset = filter.filter(self.queryset, data)
            except (TypeError, ValueError):
                # Catch errors caused by invalid initial data
                self.queryset = self.queryset.none()
        else:
            self.queryset = self.queryset.none()

        # Set the data URL on the APISelect widget (if not already set)
        widget = bound_field.field.widget
        if not widget.attrs.get("data-url"):
            data_url = reverse(
                f"{self.queryset.model._meta.app_label}-api:{self.queryset.model._meta.model_name}-list"
            )
            widget.attrs["data-url"] = data_url

        return bound_field
Пример #12
0
    def get_bound_field(self, form, field_name):
        bound_field = BoundField(form, self, field_name)

        # Set initial value based on prescribed child fields (if not already set)
        if not self.initial and self.initial_params:
            filter_kwargs = {}
            for kwarg, child_field in self.initial_params.items():
                value = form.initial.get(child_field.lstrip('$'))
                if value:
                    filter_kwargs[kwarg] = value
            if filter_kwargs:
                self.initial = self.queryset.filter(**filter_kwargs).first()

        # Modify the QuerySet of the field before we return it. Limit choices to any data already bound: Options
        # will be populated on-demand via the APISelect widget.
        data = bound_field.value()
        if data:
            field_name = getattr(self, 'to_field_name') or 'pk'
            filter = self.filter(field_name=field_name)
            try:
                self.queryset = filter.filter(self.queryset, data)
            except TypeError:
                # Catch any error caused by invalid initial data passed from the user
                self.queryset = self.queryset.none()
        else:
            self.queryset = self.queryset.none()

        # Set the data URL on the APISelect widget (if not already set)
        widget = bound_field.field.widget
        if not widget.attrs.get('data-url'):
            app_label = self.queryset.model._meta.app_label
            model_name = self.queryset.model._meta.model_name
            data_url = reverse('{}-api:{}-list'.format(app_label, model_name))
            widget.attrs['data-url'] = data_url

        return bound_field
Пример #13
0
def extract_widget_context(field: django_forms.BoundField) -> Dict[str, Any]:
    """
    Previously we used a custom FormRenderer but there is *no way* to avoid
    the built in render method from piping this into `mark_safe`.

    So we monkeypatch the widget's internal renderer to return JSON directly
    without being wrapped by `mark_safe`.
    """
    original_render = field.field.widget._render  # type: ignore[union-attr]
    field.field.widget._render = (  # type: ignore[union-attr]
        lambda template_name, context, renderer: context)
    widget = field.as_widget()
    context: Any = widget["widget"]  # type: ignore[index]
    context["template_name"] = getattr(field.field.widget,
                                       "reactivated_widget",
                                       context["template_name"])

    # This is our first foray into properly serializing widgets using the
    # serialization framework.
    #
    # Eventually all widgets can be serialized this way and the frontend widget
    # types can disappear and be generated from the code here.
    #
    # We should not just handle optgroups but every property, and do so
    # recursively.
    def handle_optgroups(widget_context: Any) -> None:
        optgroups = widget_context.get("optgroups", None)
        if optgroups is not None:
            optgroup_schema = create_schema(Optgroup, {})
            widget_context["optgroups"] = [
                serialize(optgroup, optgroup_schema) for optgroup in optgroups
            ]

    for subwidget_context in context.get("subwidgets", []):
        handle_optgroups(subwidget_context)

    handle_optgroups(context)

    field.field.widget._render = original_render  # type: ignore[union-attr]

    return context  # type: ignore[no-any-return]
Пример #14
0
    def get_bound_field(self, form, field_name):
        bound_field = BoundField(form, self, field_name)

        # Modify the QuerySet of the field before we return it. Limit choices to any
        # data already bound: Options will be populated on-demand via the APISelect
        # widget
        data = self.prepare_value(bound_field.data or bound_field.initial)
        if data:
            filter = self.filter(field_name=self.to_field_name or "pk",
                                 queryset=self.queryset)
            self.queryset = filter.filter(self.queryset, data)
        else:
            self.queryset = self.queryset.none()

        # Set the data URL on the APISelect widget (if not already set)
        widget = bound_field.field.widget
        if not widget.attrs.get("data-url"):
            data_url = reverse(
                f"{self.queryset.model._meta.app_label}-api:{self.queryset.model._meta.model_name}-list"
            )
            widget.attrs["data-url"] = data_url

        return bound_field
Пример #15
0
    def test_bound_field(self):
        unbound_field = Field()
        field = BoundField(Form(), unbound_field, "field")

        context = Context({"field": field})
        self.TEMPLATE.render(context)
Пример #16
0
 def run_field_checks(self, rendered_field: BoundField):
     if rendered_field.widget_type == 'checkbox':
         # Set custom attribute for use in the template
         rendered_field.is_checkbox = True
     if isinstance(rendered_field.field.widget, FileInput):
         self._has_file_field = True
Пример #17
0
    def test_bound_field_labels_not_boolean(self):
        unbound_field = Field()
        field = BoundField(Form(), unbound_field, "field")

        context = Context({"field": field})
        self.TEMPLATE_LABELS_NOT_BOOLEAN.render(context)
Пример #18
0
    def test_bound_field_no_labels(self):
        unbound_field = Field()
        field = BoundField(Form(), unbound_field, "field")

        context = Context({"field": field})
        self.TEMPLATE_NO_LABELS.render(context)
Пример #19
0
    def _html_output(self, normal_row, error_row, row_ender, help_text_html,
                     errors_on_separate_row):
        "Helper function for outputting HTML. Used by as_table(), as_ul(), as_p()."
        top_errors = self.non_field_errors(
        )  # Errors that should be displayed above all fields.
        output, hidden_fields = [], []

        for fieldset, fields in self.fieldsets:
            if fieldset:
                output.append(
                    normal_row % {
                        'errors': '',
                        'label': '&nbsp;',
                        'field': self.fieldset_template % fieldset,
                        'help_text': ''
                    })

            for name, field in [
                    i for i in self.fields.items() if i[0] in fields
            ]:
                bf = BoundField(self, field, name)
                bf_errors = self.error_class([
                    escape(error) for error in bf.errors
                ])  # Escape and cache in local variable.
                if bf.is_hidden:
                    if bf_errors:
                        top_errors.extend([
                            u'(Hidden field %s) %s' % (name, force_unicode(e))
                            for e in bf_errors
                        ])
                    hidden_fields.append(unicode(bf))
                else:
                    if errors_on_separate_row and bf_errors:
                        output.append(error_row % force_unicode(bf_errors))
                    if bf.label:
                        label = escape(force_unicode(bf.label))
                        # Only add the suffix if the label does not end in
                        # punctuation.
                        if self.label_suffix:
                            if label[-1] not in ':?.!':
                                label += self.label_suffix
                        label = bf.label_tag(label) or ''
                    else:
                        label = ''
                    if field.help_text:
                        help_text = help_text_html % force_unicode(
                            field.help_text)
                    else:
                        help_text = u''
                    output.append(
                        normal_row % {
                            'errors': force_unicode(bf_errors),
                            'label': force_unicode(label),
                            'field': unicode(bf),
                            'help_text': help_text
                        })

        if top_errors:
            output.insert(0, error_row % force_unicode(top_errors))
        if hidden_fields:  # Insert any hidden fields in the last row.
            str_hidden = u''.join(hidden_fields)
            if output:
                last_row = output[-1]
                # Chop off the trailing row_ender (e.g. '</td></tr>') and
                # insert the hidden fields.
                output[
                    -1] = last_row[:-len(row_ender)] + str_hidden + row_ender
            else:
                # If there aren't any rows in the output, just append the
                # hidden fields.
                output.append(str_hidden)
        return mark_safe(u'\n'.join(output))
Пример #20
0
def jet_select2_lookups(field: BoundField):
    form_field: Field = getattr(field, 'field', None)
    if not (form_field and
            (isinstance(form_field, ModelChoiceField)
             or isinstance(form_field, ModelMultipleChoiceField))):
        return field

    qs = form_field.queryset
    model = qs.model

    if not (getattr(model, 'autocomplete_search_fields', None)
            and getattr(form_field, 'autocomplete', True)):
        return field

    choices = []
    app_label = model._meta.app_label
    model_name = model._meta.object_name
    url = getattr(form_field, 'url', reverse('jet:model_lookup'))

    data = getattr(form_field.widget, 'data', {})
    data['blank'] = not form_field.required

    attrs = {
        'class': 'ajax',
        'data-app-label': app_label,
        'data-model': model_name,
        'data-ajax--url': url,
        **format_widget_data(data),
    }

    initial_value = field.value()

    if isinstance(form_field, ModelMultipleChoiceField):
        if initial_value:
            initial_objects = model.objects.filter(pk__in=initial_value)
            choices.extend([(initial_object.pk,
                             get_model_instance_label(initial_object))
                            for initial_object in initial_objects])

        if isinstance(form_field.widget, RelatedFieldWidgetWrapper):
            form_field.widget.widget = SelectMultiple(attrs)
        else:
            form_field.widget = SelectMultiple(attrs)
        form_field.choices = choices
    elif isinstance(form_field, ModelChoiceField):
        if initial_value:
            try:
                initial_object = model.objects.get(pk=initial_value)
                attrs['data-object-id'] = initial_value
                choices.append((initial_object.pk,
                                get_model_instance_label(initial_object)))
            except model.DoesNotExist:
                pass

        if isinstance(form_field.widget, RelatedFieldWidgetWrapper):
            form_field.widget.widget = Select(attrs)
        else:
            form_field.widget = Select(attrs)
        form_field.choices = choices

    return field
Пример #21
0
def class_attr(text: BoundField, args: str) -> BoundField:
    css_cls = ' '.join([c.strip() for c in args.split(',')])
    return text.as_widget(attrs={'class':'{}'.format(css_cls)})
Пример #22
0
def form_filed(field: BoundField):
    # type(filed)
    field.css_classes('layui-input')
    # field.build_widget_attrs({'class': "layui-input", })
    return mark_safe(field)
Пример #23
0
    def test_get_field_options(self):
        unbound_field = ChoiceField()
        field = BoundField(Form(), unbound_field, "field")

        context = Context({"field": field})
        self.TEMPLATE.render(context)