Проверьте на наличие ошибок и других значений на уровне виджета - возможно, используя настраиваемое поле формы - PullRequest
0 голосов
/ 02 февраля 2019

Как получить доступ, если в поле есть) ошибки на уровне виджета?

Используя значение по умолчанию, я попытался:

{% if widget.attributes.has_errors %} or {% if widget.has_errors %}

, но не работает.

Я использую пользовательские шаблоны виджетов, я думаю использовать пользовательскую форму поля и перезаписать поле по умолчанию.

Я знаю, что метод clean существует, но я не знаю, как передать динамический виджет (не по умолчанию) данные / атрибуты, которые я хочу.

Я пытался:

class AWidget(forms.Widget):

    def get_context(self, name, value, attrs):

        context = super().get_context(name, value, attrs)
        has_errors = context['widget']['attrs'].pop('has_errors', None)
         context['widget']['has_errors'] = has_errors

Это работает для errors, но я не знаю, является ли это лучшим вариантом, плюс я хочу передать другимзначения / атрибуты из поля формы, и я думаю, что будет лучше попытаться перезаписать поле формы, но я не знаю точно, как.

Также доступ к отдельным атрибутам с помощью:

 {{ widget.attrs.maxlength }} or  {{ widget.attrs.items.maxlength }}

даже если присоединяется к циклу for, работает


Я знаю, что могу добавить родительский div с классом ошибки:

 <div class="{% if form.field.errors %}pass_error{% endif %}">
        {{ form.field }} 
    </div>

, но это подразумевает большие изменения на уровне CSS.

Я уже перезаписал все виджеты Django пользовательскими виджетами, при ошибке мне не нужно простоизменить цвет границы , но чтобы показать или нет различные элементы шаблона виджета и положение некоторых из них изменилось.

Я уже изменяю основанный виджет, чтобы добавить ошибки, но я смотрю насделать это более элегантным способом на уровне поля, передав из поля виджету, параметры которого зависят от типа ошибки.

Итак, мой вопрос: что мне нужно перезаписать для перехода от поля к ошибкам виджета и другим переменным?

Ответы [ 2 ]

0 голосов
/ 07 февраля 2019

Не уверен, может ли это помочь в вашем конкретном случае использования ... но на всякий случай учтите, что когда вы создаете форму в представлении, вы можете добавлять дополнительные параметры по мере необходимости, а затем передавать их в свой пользовательский виджет.

Рабочий пример:

file "forms.py"

from django import forms


def build_ingredient_form(unit):
    """
    Ingredient form factory

    Here we build the form class dynamically, in order to acces 'unit' via closure.
    References:
        /420620/django-peredacha-polzovatelskih-parametrov-formy-v-formset#420626
    """
    class IngredientForm(forms.Form):
        #quantity = forms.DecimalField(max_digits=10)
        quantity = UnitField(unit, required=False)
        ...
    return IngredientForm


file "fields.py"

from django import forms
from .fields import UnitField


class UnitField(forms.CharField):
    """
    Custom field to support UnitWidget

    References:
        - http://tothinkornottothink.com/post/10815277049/django-forms-i-custom-fields-and-widgets-in
    """

    def __init__(self, unit, *args, **kwargs):
        self.unit = unit
        super(UnitField, self).__init__(*args, **kwargs)
        self.widget = UnitWidget(unit)

    ...

file "виджетов.py "

from django import forms
from .models import Unit


class UnitWidget(forms.TextInput):

    def __init__(self, unit, attrs=None):
        if unit is None:
            self.unit = Unit()
        else:
            self.unit = unit

    ...

0 голосов
/ 07 февраля 2019

Что ж, виджет - это то, как вы будете отображать данные / значение поля в HTML-шаблоне, это единственная функция виджетов, посмотрите следующий пример, взятый из документов:

>>> name = forms.TextInput(attrs={'required': True})
>>> name.render('name', 'A name')
'<input name="name" type="text" value="A name" required>'
>>>
>>> name = forms.TextInput(attrs={'required': False})
>>> name.render('name', 'A name')
'<input name="name" type="text" value="A name">'

Итак, виджетыне осведомлены о том, что данные действительны (есть ошибки) или нет, и должны оставаться такими.

Не рекомендуется обрабатывать ошибки / проверку данных на уровне виджетов, вы хотите, я могу гарантировать, чточто если вы измените внешний вид своего поля (виджета), ваши проверки продолжат работать.

Сказал, что ...

Как получить доступ к ошибкам поля?

Когда вы визуализируете форму, вы можете сделать это поле за полем, давайте возьмем эту форму в качестве примера:

class LoginForm(forms.Form):
    username = forms.CharField(max_length=255)
    password = forms.CharField(widget=forms.PasswordInput)

вы можете написать в temlate:

<form action="." method="get">
   <p>{{ loginform.username.label }}: {{ loginform.username }}</p>
   <p>{{ loginform.password.label }}: {{ loginform.password}}</p>
    <button type="submit">submit</button>
</form>

И это будет выглядеть примерно так:следующее:

enter image description here

Теперь предположим, что ваша форма не допускает пароли длиной менее 8 символов:

class LoginForm(forms.Form):
    username = forms.CharField(max_length=255)
    password = forms.CharField(widget=forms.PasswordInput)

    def clean_password(self):
        password = self.cleaned_data['password']
        if len(password) < 8:
            raise forms.ValidationError(
            "Password must have at least 8 characters, it has only %(password_length)s",
            code='invalid password',
            params={'password_length': len(password)}
        )
        return password

Выможет получить доступ к ошибкам пароля, как это:

<form action="." method="get">
    {% csrf_token %}
    <p>{{ form.username.label }}: {{ form.username }}</p>
    <p>{{ form.password.label }}: {{ form.password}}</p>

    <ul>
        {% for error in form.password.errors %}
            <li>{{ error }}</li>    
        {% endfor %}
    </ul>

   <button type="submit">submit</button>
</form>

И сейчасесли вы введете короткий пароль ...

enter image description here

Я хочу, чтобы элемент управления выглядел иначе, если есть ошибки.

Вы можетедобавить стиль, если есть ошибки, просто используйте {% if ... %} в коде вашего шаблона:

 <p>
    {{ form.password.label }}:
    <span class="{% if form.password.errors %}pass_error{% endif %}">
        {{ form.password }} 
    </span>
 </p>

С помощью CSS:

 <style>
    .pass_error input {
        border-color: red;
    }
 </style>

И вот результат:

enter image description here

Заключение.

Проверка и обработка ошибок данных в форме или использование проверщиков , использование виджетов для отображения данных, конечновы можете настроить представление данных, так как вы можете указать собственный шаблон для вашего виджета.

Я также рекомендую django-widget-twaeks , если вы хотите добавить атрибуты к вашему виджету вкод шаблона.Это приложение позволяет вам писать код (например, из документации приложения):

{% load widget_tweaks %}

<!-- change input type (e.g. to HTML5) -->
{% render_field form.search_query type="search" %}

<!-- add/change several attributes -->
{% render_field form.text rows="20" cols="20" title="Hello, world!" %}

<!-- append to an attribute -->
{% render_field form.title class+="css_class_1 css_class_2" %}

<!-- template variables can be used as attribute values -->
{% render_field form.text placeholder=form.text.label %}
...