我已经实现了一个扩展类,Widget
我需要为这个类实现一个验证系统,但我认为这与Field
类不兼容,因为我应用了自定义render()
方法,可能这违反了LSP 原则(不确定)。这是一个例子:
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)
django_future.py:
注意: Django1.3的six
库在这里可用:
https ://github.com/django/django/blob/1.5/django/utils/six.py
'''
This Lib contains functions from future implemantations of Django (After v1.3).
'''
from django.utils.safestring import mark_safe
from django.utils.html import conditional_escape
from django.utils import encoding
import datetime
from decimal import Decimal
#The six lib is not included in Django 1.3
#If you have 1.3 (as i have) you can search here in a future version of Django:
#django.utils -> six
import six
def flatatt(attrs):
"""
Convert a dictionary of attributes to a single string.
The returned string will contain a leading space followed by key="value",
XML-style pairs. It is assumed that the keys do not need to be XML-escaped.
If the passed dictionary is empty, then return an empty string.
The result is passed through 'mark_safe'.
"""
return format_html_join('', ' {0}="{1}"', sorted(attrs.items()))
def format_html(format_string, *args, **kwargs):
#django.utils.html
"""
Similar to str.format, but passes all arguments through conditional_escape,
and calls 'mark_safe' on the result. This function should be used instead
of str.format or % interpolation to build up small HTML fragments.
"""
args_safe = map(conditional_escape, args)
kwargs_safe = dict([(k, conditional_escape(v)) for (k, v) in
six.iteritems(kwargs)])
return mark_safe(format_string.format(*args_safe, **kwargs_safe))
def format_html_join(sep, format_string, args_generator):
#django.utils.html
"""
A wrapper of format_html, for the common case of a group of arguments that
need to be formatted using the same format string, and then joined using
'sep'. 'sep' is also passed through conditional_escape.
'args_generator' should be an iterator that returns the sequence of 'args'
that will be passed to format_html.
Example:
format_html_join('\n', "<li>{0} {1}</li>", ((u.first_name, u.last_name)
for u in users))
"""
return mark_safe(conditional_escape(sep).join(
format_html(format_string, *tuple(args))
for args in args_generator))
def is_protected_type(obj):
return isinstance(obj, six.integer_types + (type(None), float, Decimal,
datetime.datetime, datetime.date, datetime.time))
def force_text(s, encoding='utf-8', strings_only=False, errors='strict'):
if isinstance(s, six.text_type):
return s
if strings_only and is_protected_type(s):
return s
try:
if not isinstance(s, six.string_types):
if hasattr(s, '__unicode__'):
s = s.__unicode__()
else:
if six.PY3:
if isinstance(s, bytes):
s = six.text_type(s, encoding, errors)
else:
s = six.text_type(s)
else:
s = six.text_type(bytes(s), encoding, errors)
else:
s = s.decode(encoding, errors)
except UnicodeDecodeError as e:
if not isinstance(s, Exception):
raise encoding.DjangoUnicodeDecodeError(s, *e.args)
else:
s = ' '.join([force_text(arg, encoding, strings_only,
errors) for arg in s])
return s
所以,我想问一下Field
类(或Form
类)究竟如何从 中获取原始值(html),Widget
以及如何应用验证过滤器并返回结果。请提供一个带有描述的小示例,以便理解该过程。
*请注意,我已经看过 [Django 代码][3],不幸的是我无法完全理解该过程。
谢谢是提前。