Python Django:Form或Field类如何呈现小部件?什么';过程是什么?

Python Django:Form或Field类如何呈现小部件?什么';过程是什么?,python,django,forms,validation,widget,Python,Django,Forms,Validation,Widget,我已经实现了一个扩展Widget的类,我需要为这个类实现一个验证系统,但我认为它与Field类不兼容,因为我已经应用了自定义render()方法,这可能违反了(不确定)。以下是一个例子: from django import forms from django.utils.safestring import mark_safe from django.utils.encoding import force_unicode from django.utils import formats from

我已经实现了一个扩展
Widget
的类,我需要为这个类实现一个验证系统,但我认为它与
Field
类不兼容,因为我已经应用了自定义
render()
方法,这可能违反了(不确定)。以下是一个例子:

from django import forms
from django.utils.safestring import mark_safe
from django.utils.encoding import force_unicode
from django.utils import formats
from django_future import format_html, flatatt

class InputGeneric(forms.Widget):
"""
Base class for all <input> widgets
"""
input_type = None # Subclasses must define this.
_to_str = None

def __init__(self, attrs=None, single_attrs=None):
    super(InputGeneric, self).__init__(attrs)
    self.single_attrs = single_attrs or ''

def get_attrs(self):
    return self.attrs

def get_attr(self, key):
    return self.attrs.get(key, None)

def render(self, name=None, value=None, attrs=None, single_attrs=None):
    '''
    *The default arguments of this function are:
    (self, name, value, attrs=None)
    - - - -
    single_attrs: is a string of HTML5 single attributes like "required", disabled"
    Example:
    render(single_attrs='required disabled')
    '''
    name = name or self.attrs.get('name', None)

    if name:
        final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
    else:
        final_attrs = self.build_attrs(attrs, type=self.input_type)

    value = self.attrs.get('value', None)
    if value:
        # Only add the 'value' attribute if a value is non-empty.
        final_attrs['value'] = force_unicode(self._format_value(value))

    self._to_str = format_html('<input{0} {1} />', flatatt(final_attrs), single_attrs)
    return self._to_str

def get_rendered(self):
    return self.render(attrs=self.attrs, single_attrs=self.single_attrs)

def __str__(self):
    if self._to_str:
        return self._to_str
    self._to_str = self.render()
    return self._to_str

class InputText(InputGeneric):
input_type = 'text'

def __init__(self, attrs=None, single_attrs=None):
    if attrs.get('type', None) is not None:
        del attrs['type']
    super(InputText, self).__init__(attrs, single_attrs)
因此,我想问一下
字段
类(或
表单
类)如何从
小部件
获取原始值(html),以及如何应用验证过滤器并返回结果。请提供一个带有说明的小示例,以了解流程

*注意我已经看过[Django代码][3],不幸的是我无法完全理解这个过程


首先,我不得不说我的方法是不正确的。从
render()
的参数中删除
name
value
是错误的决定,因为这确实违反了LSP原则。此外,输入字段最基本的内容是
name
value
,它们也包含在POST请求中

之后,我发现了内部的渲染过程。小部件在
BoundField()
类中呈现,该类在调用时自动调用
as\u小部件()
函数。渲染的所有过程也是如此

接下来,我用一个示例应用程序演示这个过程

应用程序结构
1) 首先,我们要上表单课:

my_form.py: 3) 模板:

contact.html 3) 上面的函数调用另一个名为
self.\u html\u output(…)
的函数,当然,它位于
BaseForm()中。此函数负责输出通过调用其他较小的函数或类呈现的最终结果

一些注释
  • 当在views.py内执行
    form=ContactForm()
    时,我们知道称为
    ContactForm()
    类。但是这个类是生活在forms.py中的
    Form
    的子类,
    Form()
    也是
    BaseForm()
    类的子类。这意味着
    ContactForm()
    继承了
    BaseForm()
    的所有内容
  • Form()
    类为空。仅继承自
    BaseForm()
    ,用于继承目的。每个表单的真正父级是
    BaseForm()
    class
  • 在初始化时,
    ContactForm()
    和他的父母
    Form()
    BaseForm()
    调用一些非常重要的变量,例如
    self.fields
    ,其中包含孩子的所有字段。在我们的示例中:
    主题
    电子邮件
    消息
    。 其他重要变量包括:
    • self.data
      :包含POST数据
    • self.\u errors
      :调用clean()后存储错误
\u html\u output()的内部

此函数迭代
self.fields
(在我们的例子中是通过
subject
email
message
)并为每个字段调用类
BoundField()
,如下所示:

bf=BoundField(frm\u clss,field,name)

第一个参数
frm\u clss
BaseForm()
类。第二个是字段列表中的当前字段(例如,
主题
),第三个是
ContactForm()
中给出的字段的实际名称,因此这三个名称是:“主题”、“电子邮件”和“消息”

最后,该函数返回所有呈现的小部件的“已编译”和标记的安全字符串

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
    })

    .
    .
    .

return mark_safe(u'\n'.join(output))
BoundField()类

默认情况下,调用小部件的
render()
方法,并将html字符串返回到
BaseForm()
类(
\u html\u output()
)。

首先,我必须说我的方法不正确。从
render()
的参数中删除
name
value
是错误的决定,因为这确实违反了LSP原则。此外,输入字段最基本的内容是
name
value
,它们也包含在POST请求中

之后,我发现了内部的渲染过程。小部件在
BoundField()
类中呈现,该类在调用时自动调用
as\u小部件()
函数。渲染的所有过程也是如此

接下来,我用一个示例应用程序演示这个过程

应用程序结构
1) 首先,我们要上表单课:

my_form.py: 3) 模板:

contact.html 3) 上面的函数调用另一个名为
self.\u html\u output(…)
的函数,当然,它位于
BaseForm()中。此函数负责输出通过调用其他较小的函数或类呈现的最终结果

一些注释
  • 当在views.py内执行
    form=ContactForm()
    时,我们知道称为
    ContactForm()
    类。但是这个类是生活在forms.py中的
    Form
    的子类,
    Form()
    也是
    BaseForm()
    类的子类。这意味着
    ContactForm()
    继承了
    BaseForm()
    的所有内容
  • Form()
    类为空。仅继承自
    BaseForm()
    ,用于继承目的。每个表单的真正父级是
    BaseForm()
    class
  • 在初始化时,
    ContactForm()
    和他的父母
    Form()
    BaseForm()
    调用一些非常重要的变量,例如
    self.fields
    ,其中包含孩子的所有字段。在我们的示例中:
    主题
    电子邮件
    消息
    。 其他重要变量包括:
    • self.data
      from django import forms
      
      class ContactForm(forms.Form):
          subject = forms.CharField(min_length = 2, max_length = 100, widget = forms.TextInput(attrs = {'placeholder':'Type a subject...'}))
          email = forms.EmailField(required=True, widget = forms.TextInput(attrs={'class': 'span3', 'placeholder': 'Your email...'}))
          message = forms.CharField(widget=forms.Textarea(attrs={'rows': '5', 'placeholder': 'Type a message...'}))
      
          def clean_message(self):
              message = self.cleaned_data['message']
              num_words = len(message.split())
              if num_words < 4:
                  raise forms.ValidationError("Not enough words!")
                  return message
      
      def contact(request):
          if request.method == 'POST':
              form = ContactForm(request.POST)
              if form.is_valid():
                  cd = form.cleaned_data
                  try:
                      send_mail(
                          cd['subject'],
                          cd['message'],
                          cd.get('email', 'noreply@anonymous.com'),
                          ['myemail@ahost.com'],
                      )
                  except BadHeaderError:
                      return HttpResponse('Invalid header found.')
      
                  return HttpResponseRedirect('thank-you/')
          else:
              form = ContactForm()
      
          return render_to_response('/contact.html', {'form': form})
      
      {% if form.errors %}
          <p style="color: red;">
              Please correct the error{{ form.errors|pluralize }} below.
          </p>
      {% endif %}
      
      <form action="" method="post">
          <fieldset>
              <legend>Contact</legend>
              <div class="field">
                  {{ form.subject.errors }}
              </div>
              {{ form.as_table }}
              <br />
              <button type="submit" class="btn">Submit</button>
          </fieldset>
      </form>
      
      def as_table(self):
          "Returns this form rendered as HTML <tr>s -- excluding the <table></table>."
          return self._html_output(
              normal_row = u'<tr%(html_class_attr)s><th>%(label)s</th><td>%(errors)s%(field)s%(help_text)s</td></tr>',
              error_row = u'<tr><td colspan="2">%s</td></tr>',
              row_ender = u'</td></tr>',
              help_text_html = u'<br /><span class="helptext">%s</span>',
              errors_on_separate_row = False)
      
      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
          })
      
          .
          .
          .
      
      return mark_safe(u'\n'.join(output))