代码之家  ›  专栏  ›  技术社区  ›  user3541631

检查小部件级别的错误和其他值-可能使用自定义表单字段

  •  6
  • user3541631  · 技术社区  · 6 年前

    如果一个字段在小部件级别有)错误,我如何访问?

    我尝试使用默认值:

    {% 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 回复  |  直到 5 年前
        1
  •  3
  •   Mario Orlandi    6 年前

    不确定这是否对您的特定用例有帮助…但为了以防万一,请注意,当您在视图中构建表单时,您可以根据需要添加额外的参数,然后将它们传递给您的自定义小部件。

    工作示例:

    文件“表单.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:
            http://stackoverflow.com/questions/622982/django-passing-custom-form-parameters-to-formset#623030
        """
        class IngredientForm(forms.Form):
            #quantity = forms.DecimalField(max_digits=10)
            quantity = UnitField(unit, required=False)
            ...
        return IngredientForm
    
    
    

    文件“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)
    
        ...
    
    

    文件“widgets.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
    
        ...
    
    
        2
  •  3
  •   Raydel Miranda    6 年前

    窗口小部件是如何将字段的数据/值呈现到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

    结论。

    验证和处理表单中的数据错误或使用 validators 使用小部件来显示数据,当然,您可以自定义数据的显示方式,因为您可以为小部件指定自定义模板。

    我也推荐 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 %}