1
0
mirror of https://github.com/django/django.git synced 2025-07-04 17:59:13 +00:00

newforms-admin: Merged to [5325]

git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@5326 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Joseph Kocherhans 2007-05-24 04:00:19 +00:00
parent 3eab964332
commit 659d99b7af
41 changed files with 5671 additions and 1575 deletions

View File

@ -41,7 +41,6 @@ And here is an inevitably incomplete list of MUCH-APPRECIATED CONTRIBUTORS --
people who have submitted patches, reported bugs, added translations, helped
answer newbie questions, and generally made Django that much better:
adurdin@gmail.com
alang@bright-green.com
Marty Alchin <gulopine@gamemusic.org>
Daniel Alves Barbosa de Oliveira Vaz <danielvaz@gmail.com>
@ -90,6 +89,7 @@ answer newbie questions, and generally made Django that much better:
dne@mayonnaise.net
Maximillian Dornseif <md@hudora.de>
Jeremy Dunck <http://dunck.us/>
Andrew Durdin <adurdin@gmail.com>
Andy Dustman <farcepest@gmail.com>
Clint Ecker
enlight

File diff suppressed because it is too large Load Diff

View File

@ -3,20 +3,19 @@
# Copyright (C)
# This file is distributed under the same license as the PACKAGE package.
#
# Jorge Gajon <gajon@gajon.org>, 2005.
# Marc Fargas <marc@fargas.com>, 2007.
msgid ""
msgstr ""
"Project-Id-Version: djangojs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-02-15 11:05+1100\n"
"PO-Revision-Date: 2007-01-19 10:30+0100\n"
"POT-Creation-Date: 2007-05-20 18:25+0200\n"
"PO-Revision-Date: 2007-05-20 18:24+0200\n"
"Last-Translator: Marc Fargas <marc@fargas.com>\n"
"Language-Team: <es@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ISO-8859-1\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: KBabel 1.11.4\n"
"X-Generator: VIM 7.0\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: contrib/admin/media/js/SelectFilter2.js:33
#, perl-format
@ -54,7 +53,7 @@ msgid ""
"January February March April May June July August September October November "
"December"
msgstr ""
"Febrer Març Abril Maig Juny Juliol Agost Setembre Octubre Novembre Desembre"
"Febrer Març Abril Maig Juny Juliol Agost Setembre Octubre Novembre Desembre"
#: contrib/admin/media/js/dateparse.js:33
msgid "Sunday Monday Tuesday Wednesday Thursday Friday Saturday"
@ -92,7 +91,7 @@ msgstr "Migdia"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:88
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:183
msgid "Cancel"
msgstr "Cancel·lar"
msgstr "Cancel·lar"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:128
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:177
@ -109,7 +108,7 @@ msgstr "Ahir"
#: contrib/admin/media/js/admin/DateTimeShortcuts.js:179
msgid "Tomorrow"
msgstr "Demà"
msgstr "Demà"
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:34
#: contrib/admin/media/js/admin/CollapsedFieldsets.js:72

View File

@ -2,19 +2,19 @@
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# pavithran <pavithran.s@gmail.com>, 2007.
msgid ""
msgstr ""
"Project-Id-Version: django\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2006-09-25 15:43+0200\n"
"PO-Revision-Date: 2007-02-28 18:35+0530\n"
"PO-Revision-Date: 2007-05-19 12:44+0530\n"
"Last-Translator: pavithran <pavithran.s@gmail.com>\n"
"Language-Team: Telugu <indlinux-telugu@lists.sourceforge.net>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: KBabel 1.11.4\n"
"Plural-Forms: nplurals=2; nplurals=n>1;"
#: contrib/comments/models.py:67 contrib/comments/models.py:166
msgid "object ID"
@ -144,7 +144,7 @@ msgstr "కర్మ స్కొరులు"
#: contrib/comments/models.py:242
#, python-format
msgid "%(score)d rating by %(user)s"
msgstr "%(user) రేటింగ్"
msgstr "%(score)d కి %(user)s రేటింగ్"
#: contrib/comments/models.py:258
#, python-format
@ -153,9 +153,9 @@ msgid ""
"\n"
"%(text)s"
msgstr ""
"%(user)s చేత చేయబడ్డ వ్యాఖ్యానములు"
"%(user)s చేత చేయబడ్డ వ్యాఖ్యానములు:\n"
"\n"
"%(text)లు"
"%(text)s"
#: contrib/comments/models.py:265
msgid "flag date"
@ -220,12 +220,12 @@ msgid_plural ""
"\n"
"%(text)s"
msgstr[0] ""
"ఈ వ్యాఖ్యానము చేసిన యూజర్ %(count)లు కన్న తక్కువ సమర్పించాడు "
"ఈ వ్యాఖ్యానము చేసిన యూజర్ %(count)s లు కన్న తక్కువ సమర్పించాడు "
"వ్యాఖ్యానము:\n"
"\n"
"%(text)s"
msgstr[1] ""
"ఈ వ్యాఖ్యానము చేసిన యూజర్ %(count)లు కన్న తక్కువ సమర్పించాడు"
"ఈ వ్యాఖ్యానము చేసిన యూజర్ %(count)s లు కన్న తక్కువ సమర్పించాడు"
"వ్యాఖ్యానములు:\n"
"\n"
"%(text)s"
@ -343,7 +343,8 @@ msgstr "మీ పేరు"
msgid ""
"<h3>By %s:</h3>\n"
"<ul>\n"
msgstr "<h3> %s తో:</h3>\n"
msgstr ""
"<h3> %s తో:</h3>\n"
"<ul>\n"
#: contrib/admin/filterspecs.py:70 contrib/admin/filterspecs.py:88
@ -513,17 +514,17 @@ msgstr "%s ని మార్చంది"
#: contrib/admin/views/main.py:473
#, python-format
msgid "One or more %(fieldname)s in %(name)s: %(obj)s"
msgstr "ఒకటి కాని ,అంత కన్నఎక్కువ %(name)లు లో %(fieldname)లు : %(obj)లు "
msgstr "ఒకటి కాని ,అంత కన్నఎక్కువ %(name)s లో %(fieldname)s : %(obj)s "
#: contrib/admin/views/main.py:478
#, python-format
msgid "One or more %(fieldname)s in %(name)s:"
msgstr "ఒకటి కాని ,అంత కన్నఎక్కువ %(name)లు లో %(fieldname)లు"
msgstr "ఒకటి కాని ,అంత కన్నఎక్కువ %(name)s లో %(fieldname)s"
#: contrib/admin/views/main.py:511
#, python-format
msgid "The %(name)s \"%(obj)s\" was deleted successfully."
msgstr "%(name)లు \"%(obj)s\"జయప్రదంగా తీసివేయబడ్డడి"
msgstr "%(name)s \"%(obj)s\"జయప్రదంగా తీసివేయబడ్డడి"
#: contrib/admin/views/main.py:514
msgid "Are you sure?"
@ -532,7 +533,7 @@ msgstr "మీరు కచ్చితంగా ఉన్నారా?"
#: contrib/admin/views/main.py:536
#, python-format
msgid "Change history: %s"
msgstr "మార్చబడిన పురాణము"
msgstr "మార్చబడిన పురాణము: %s"
#: contrib/admin/views/main.py:570
#, python-format
@ -796,12 +797,12 @@ msgstr "క్షమించండి మీరు కోరిన పేజి
#: contrib/admin/templates/admin/index.html:17
#, python-format
msgid "Models available in the %(name)s application."
msgstr "మొడల్ లు %(name)లో దొరికే అప్ప్లికేషన్"
msgstr "మొడల్ లు %(name)s లో దొరికే అప్ప్లికేషన్"
#: contrib/admin/templates/admin/index.html:18
#, python-format
msgid "%(name)s"
msgstr "%(name)లు"
msgstr "%(name)s"
#: contrib/admin/templates/admin/index.html:28
#: contrib/admin/templates/admin/change_form.html:15
@ -831,7 +832,7 @@ msgstr "ఏమి దొరకలేదు"
#: contrib/admin/templates/admin/change_list.html:11
#, python-format
msgid "Add %(name)s"
msgstr "%(name)లు జత చేయు"
msgstr "%(name)s జత చేయు"
#: contrib/admin/templates/admin/login.html:22
msgid "Have you <a href=\"/password_reset/\">forgotten your password</a>?"
@ -1794,7 +1795,7 @@ msgstr "సంవత్సరము 1900 లేక దాని తరువా
#: core/validators.py:142
#, python-format
msgid "Invalid date: %s."
msgstr "సరికాని తారీఖు"
msgstr "సరికాని తారీఖు : %s."
#: core/validators.py:146 db/models/fields/__init__.py:415
msgid "Enter a valid date in YYYY-MM-DD format."
@ -1846,8 +1847,10 @@ msgstr "సరైన URL కావాలి"
msgid ""
"Valid HTML is required. Specific errors are:\n"
"%s"
msgstr "సరైన HTML ఇవ్వండి .ప్రత్యేకమైన తప్పులు :\n"
msgstr ""
"సరైన HTML ఇవ్వండి .ప్రత్యేకమైన తప్పులు :\n"
"%s"
#: core/validators.py:220
#, python-format
msgid "Badly formed XML: %s"
@ -1856,7 +1859,7 @@ msgstr ""
#: core/validators.py:230
#, python-format
msgid "Invalid URL: %s"
msgstr ""
msgstr "సరికాని URL: %s"
#: core/validators.py:234 core/validators.py:236
#, python-format
@ -2004,27 +2007,27 @@ msgstr ""
#: views/generic/create_update.py:43
#, python-format
msgid "The %(verbose_name)s was created successfully."
msgstr "%(verbose_name)లు జయప్రదంగా తయారయింది"
msgstr "%(verbose_name)s జయప్రదంగా తయారయింది"
#: views/generic/create_update.py:117
#, python-format
msgid "The %(verbose_name)s was updated successfully."
msgstr "%(verbose_name)లు జయప్రదంగా @@"
msgstr "%(verbose_name)s జయప్రదంగా @@"
#: views/generic/create_update.py:184
#, python-format
msgid "The %(verbose_name)s was deleted."
msgstr "%(verbose_name)లు తీసివేయబడినది"
msgstr "%(verbose_name)s తీసివేయబడినది"
#: db/models/manipulators.py:302
#, python-format
msgid "%(object)s with this %(type)s already exists for the given %(field)s."
msgstr "%(field)ల లో %(object)తో %(type) ఉన్నాయి"
msgstr "%(field)s లో %(object)s తో %(type)s ఉన్నాయి"
#: db/models/fields/__init__.py:40
#, python-format
msgid "%(optname)s with this %(fieldname)s already exists."
msgstr "%(optname)లు తో %(fieldname) ముందే ఉన్నాయి ."
msgstr "%(optname)s తో %(fieldname)s ముందే ఉన్నాయి ."
#: db/models/fields/__init__.py:114 db/models/fields/__init__.py:265
#: db/models/fields/__init__.py:551 db/models/fields/__init__.py:562
@ -2082,7 +2085,7 @@ msgstr "లైన్ బ్రేక్స్ కి ఇక్కడ ఆన
#: forms/__init__.py:487 forms/__init__.py:560 forms/__init__.py:599
#, python-format
msgid "Select a valid choice; '%(data)s' is not in %(choices)s."
msgstr "సరైనది ఎంచుకోండి; %(choices) లో '%(data)s' లేవు "
msgstr "సరైనది ఎంచుకోండి; %(choices)s లో '%(data)s' లేవు "
#: forms/__init__.py:663
msgid "The submitted file is empty."

View File

@ -72,6 +72,7 @@ def result_headers(cl):
for i, field_name in enumerate(cl.list_display):
try:
f = lookup_opts.get_field(field_name)
admin_order_field = None
except models.FieldDoesNotExist:
# For non-field list_display values, check for the function
# attribute "short_description". If that doesn't exist, fall
@ -86,7 +87,8 @@ def result_headers(cl):
header = field_name.replace('_', ' ')
# It is a non-field, but perhaps one that is sortable
if not getattr(getattr(cl.model, field_name), "admin_order_field", None):
admin_order_field = getattr(getattr(cl.model, field_name), "admin_order_field", None)
if not admin_order_field:
yield {"text": header}
continue
@ -101,7 +103,7 @@ def result_headers(cl):
th_classes = []
new_order_type = 'asc'
if field_name == cl.order_field:
if field_name == cl.order_field or admin_order_field == cl.order_field:
th_classes.append('sorted %sending' % cl.order_type.lower())
new_order_type = {'asc': 'desc', 'desc': 'asc'}[cl.order_type.lower()]
@ -166,8 +168,8 @@ def items_for_result(cl, result):
# Booleans are special: We use images.
elif isinstance(f, models.BooleanField) or isinstance(f, models.NullBooleanField):
result_repr = _boolean_icon(field_val)
# FloatFields are special: Zero-pad the decimals.
elif isinstance(f, models.FloatField):
# DecimalFields are special: Zero-pad the decimals.
elif isinstance(f, models.DecimalField):
if field_val is not None:
result_repr = ('%%.%sf' % f.decimal_places) % field_val
else:

View File

@ -36,6 +36,9 @@ class SessionWrapper(object):
def get(self, key, default=None):
return self._session.get(key, default)
def pop(self, key, *args):
return self._session.pop(key, *args)
def set_test_cookie(self):
self[TEST_COOKIE_NAME] = TEST_COOKIE_VALUE

View File

@ -0,0 +1,19 @@
r"""
>>> s = SessionWrapper(None)
Inject data into the session cache.
>>> s._session_cache = {}
>>> s._session_cache['some key'] = 'exists'
>>> s.pop('some key')
'exists'
>>> s.pop('some key', 'does not exist')
'does not exist'
"""
from django.contrib.sessions.middleware import SessionWrapper
if __name__ == '__main__':
import doctest
doctest.testmod()

View File

@ -870,7 +870,7 @@ def inspectdb():
if field_type == 'CharField' and row[3]:
extra_params['maxlength'] = row[3]
if field_type == 'FloatField':
if field_type == 'DecimalField':
extra_params['max_digits'] = row[4]
extra_params['decimal_places'] = row[5]
@ -945,11 +945,11 @@ def get_validation_errors(outfile, app=None):
e.add(opts, '"%s": You can\'t use "id" as a field name, because each model automatically gets an "id" field if none of the fields have primary_key=True. You need to either remove/rename your "id" field or add primary_key=True to a field.' % f.name)
if isinstance(f, models.CharField) and f.maxlength in (None, 0):
e.add(opts, '"%s": CharFields require a "maxlength" attribute.' % f.name)
if isinstance(f, models.FloatField):
if isinstance(f, models.DecimalField):
if f.decimal_places is None:
e.add(opts, '"%s": FloatFields require a "decimal_places" attribute.' % f.name)
e.add(opts, '"%s": DecimalFields require a "decimal_places" attribute.' % f.name)
if f.max_digits is None:
e.add(opts, '"%s": FloatFields require a "max_digits" attribute.' % f.name)
e.add(opts, '"%s": DecimalFields require a "max_digits" attribute.' % f.name)
if isinstance(f, models.FileField) and not f.upload_to:
e.add(opts, '"%s": FileFields require an "upload_to" attribute.' % f.name)
if isinstance(f, models.ImageField):

View File

@ -4,19 +4,24 @@ Serialize data to/from JSON
import datetime
from django.utils import simplejson
from django.utils.simplejson import decoder
from django.core.serializers.python import Serializer as PythonSerializer
from django.core.serializers.python import Deserializer as PythonDeserializer
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
try:
import decimal
except ImportError:
from django.utils import _decimal as decimal # Python 2.3 fallback
class Serializer(PythonSerializer):
"""
Convert a queryset to JSON.
"""
def end_serialization(self):
simplejson.dump(self.objects, self.stream, cls=DateTimeAwareJSONEncoder, **self.options)
simplejson.dump(self.objects, self.stream, cls=DjangoJSONEncoder, **self.options)
def getvalue(self):
if callable(getattr(self.stream, 'getvalue', None)):
@ -33,9 +38,9 @@ def Deserializer(stream_or_string, **options):
for obj in PythonDeserializer(simplejson.load(stream)):
yield obj
class DateTimeAwareJSONEncoder(simplejson.JSONEncoder):
class DjangoJSONEncoder(simplejson.JSONEncoder):
"""
JSONEncoder subclass that knows how to encode date/time types
JSONEncoder subclass that knows how to encode date/time and decimal types.
"""
DATE_FORMAT = "%Y-%m-%d"
@ -48,5 +53,11 @@ class DateTimeAwareJSONEncoder(simplejson.JSONEncoder):
return o.strftime(self.DATE_FORMAT)
elif isinstance(o, datetime.time):
return o.strftime(self.TIME_FORMAT)
elif isinstance(o, decimal.Decimal):
return str(o)
else:
return super(DateTimeAwareJSONEncoder, self).default(o)
return super(DjangoJSONEncoder, self).default(o)
# Older, deprecated class name (for backwards compatibility purposes).
DateTimeAwareJSONEncoder = DjangoJSONEncoder

View File

@ -25,6 +25,7 @@ email_re = re.compile(
r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain
decimal_re = re.compile(r'^-?(?P<digits>\d+)(\.(?P<decimals>\d+))?$')
integer_re = re.compile(r'^-?\d+$')
ip4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$')
phone_re = re.compile(r'^[A-PR-Y0-9]{3}-[A-PR-Y0-9]{3}-[A-PR-Y0-9]{4}$', re.IGNORECASE)
@ -406,27 +407,34 @@ class IsAPowerOf(object):
if val != int(val):
raise ValidationError, gettext("This value must be a power of %s.") % self.power_of
class IsValidFloat(object):
class IsValidDecimal(object):
def __init__(self, max_digits, decimal_places):
self.max_digits, self.decimal_places = max_digits, decimal_places
def __call__(self, field_data, all_data):
match = decimal_re.search(str(field_data))
if not match:
raise ValidationError, gettext("Please enter a valid decimal number.")
digits = len(match.group('digits') or '')
decimals = len(match.group('decimals') or '')
if digits + decimals > self.max_digits:
raise ValidationError, ngettext("Please enter a valid decimal number with at most %s total digit.",
"Please enter a valid decimal number with at most %s total digits.", self.max_digits) % self.max_digits
if digits > (self.max_digits - self.decimal_places):
raise ValidationError, ngettext( "Please enter a valid decimal number with a whole part of at most %s digit.",
"Please enter a valid decimal number with a whole part of at most %s digits.", str(self.max_digits-self.decimal_places)) % str(self.max_digits-self.decimal_places)
if decimals > self.decimal_places:
raise ValidationError, ngettext("Please enter a valid decimal number with at most %s decimal place.",
"Please enter a valid decimal number with at most %s decimal places.", self.decimal_places) % self.decimal_places
def isValidFloat(field_data, all_data):
data = str(field_data)
try:
float(data)
except ValueError:
raise ValidationError, gettext("Please enter a valid decimal number.")
# Negative floats require more space to input.
max_allowed_length = data.startswith('-') and (self.max_digits + 2) or (self.max_digits + 1)
if len(data) > max_allowed_length:
raise ValidationError, ngettext("Please enter a valid decimal number with at most %s total digit.",
"Please enter a valid decimal number with at most %s total digits.", self.max_digits) % self.max_digits
if (not '.' in data and len(data) > (max_allowed_length - self.decimal_places - 1)) or ('.' in data and len(data) > (max_allowed_length - (self.decimal_places - len(data.split('.')[1])))):
raise ValidationError, ngettext( "Please enter a valid decimal number with a whole part of at most %s digit.",
"Please enter a valid decimal number with a whole part of at most %s digits.", str(self.max_digits-self.decimal_places)) % str(self.max_digits-self.decimal_places)
if '.' in data and len(data.split('.')[1]) > self.decimal_places:
raise ValidationError, ngettext("Please enter a valid decimal number with at most %s decimal place.",
"Please enter a valid decimal number with at most %s decimal places.", self.decimal_places) % self.decimal_places
raise ValidationError, gettext("Please enter a valid floating point number.")
class HasAllowableSize(object):
"""

View File

@ -5,9 +5,10 @@ DATA_TYPES = {
'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
'DateField': 'smalldatetime',
'DateTimeField': 'smalldatetime',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'FileField': 'varchar(100)',
'FilePathField': 'varchar(100)',
'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'FloatField': 'double precision',
'ImageField': 'varchar(100)',
'IntegerField': 'int',
'IPAddressField': 'char(15)',

View File

@ -36,6 +36,8 @@ IntegrityError = Database.IntegrityError
django_conversions = conversions.copy()
django_conversions.update({
FIELD_TYPE.TIME: util.typecast_time,
FIELD_TYPE.DECIMAL: util.typecast_decimal,
FIELD_TYPE.NEWDECIMAL: util.typecast_decimal,
})
# This should match the numerical portion of the version numbers (we can treat

View File

@ -9,9 +9,10 @@ DATA_TYPES = {
'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
'DateField': 'date',
'DateTimeField': 'datetime',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'FileField': 'varchar(100)',
'FilePathField': 'varchar(100)',
'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'FloatField': 'double precision',
'ImageField': 'varchar(100)',
'IntegerField': 'integer',
'IPAddressField': 'char(15)',

View File

@ -76,7 +76,7 @@ def get_indexes(cursor, table_name):
DATA_TYPES_REVERSE = {
FIELD_TYPE.BLOB: 'TextField',
FIELD_TYPE.CHAR: 'CharField',
FIELD_TYPE.DECIMAL: 'FloatField',
FIELD_TYPE.DECIMAL: 'DecimalField',
FIELD_TYPE.DATE: 'DateField',
FIELD_TYPE.DATETIME: 'DateTimeField',
FIELD_TYPE.DOUBLE: 'FloatField',

View File

@ -24,6 +24,7 @@ django_conversions.update({
FIELD_TYPE.DATETIME: util.typecast_timestamp,
FIELD_TYPE.DATE: util.typecast_date,
FIELD_TYPE.TIME: util.typecast_time,
FIELD_TYPE.DECIMAL: util.typecast_decimal,
})
# This should match the numerical portion of the version numbers (we can treat

View File

@ -9,9 +9,10 @@ DATA_TYPES = {
'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
'DateField': 'date',
'DateTimeField': 'datetime',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'FileField': 'varchar(100)',
'FilePathField': 'varchar(100)',
'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'FloatField': 'double precision',
'ImageField': 'varchar(100)',
'IntegerField': 'integer',
'IPAddressField': 'char(15)',

View File

@ -76,7 +76,7 @@ def get_indexes(cursor, table_name):
DATA_TYPES_REVERSE = {
FIELD_TYPE.BLOB: 'TextField',
FIELD_TYPE.CHAR: 'CharField',
FIELD_TYPE.DECIMAL: 'FloatField',
FIELD_TYPE.DECIMAL: 'DecimalField',
FIELD_TYPE.DATE: 'DateField',
FIELD_TYPE.DATETIME: 'DateTimeField',
FIELD_TYPE.DOUBLE: 'FloatField',

View File

@ -5,9 +5,10 @@ DATA_TYPES = {
'CommaSeparatedIntegerField': 'varchar2(%(maxlength)s)',
'DateField': 'date',
'DateTimeField': 'date',
'DecimalField': 'number(%(max_digits)s, %(decimal_places)s)',
'FileField': 'varchar2(100)',
'FilePathField': 'varchar2(100)',
'FloatField': 'number(%(max_digits)s, %(decimal_places)s)',
'FloatField': 'double precision',
'ImageField': 'varchar2(100)',
'IntegerField': 'integer',
'IPAddressField': 'char(15)',

View File

@ -46,5 +46,5 @@ DATA_TYPES_REVERSE = {
1114: 'DateTimeField',
1184: 'DateTimeField',
1266: 'TimeField',
1700: 'FloatField',
1700: 'DecimalField',
}

View File

@ -249,6 +249,7 @@ except AttributeError:
Database.register_type(Database.new_type((1083,1266), "TIME", util.typecast_time))
Database.register_type(Database.new_type((1114,1184), "TIMESTAMP", util.typecast_timestamp))
Database.register_type(Database.new_type((16,), "BOOLEAN", util.typecast_boolean))
Database.register_type(Database.new_type((1700,), "NUMERIC", util.typecast_decimal))
OPERATOR_MAPPING = {
'exact': '= %s',

View File

@ -9,9 +9,10 @@ DATA_TYPES = {
'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
'DateField': 'date',
'DateTimeField': 'timestamp with time zone',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'FileField': 'varchar(100)',
'FilePathField': 'varchar(100)',
'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'FloatField': 'double precision',
'ImageField': 'varchar(100)',
'IntegerField': 'integer',
'IPAddressField': 'inet',

View File

@ -72,6 +72,7 @@ DATA_TYPES_REVERSE = {
21: 'SmallIntegerField',
23: 'IntegerField',
25: 'TextField',
701: 'FloatField',
869: 'IPAddressField',
1043: 'CharField',
1082: 'DateField',
@ -79,5 +80,5 @@ DATA_TYPES_REVERSE = {
1114: 'DateTimeField',
1184: 'DateTimeField',
1266: 'TimeField',
1700: 'FloatField',
1700: 'DecimalField',
}

View File

@ -72,6 +72,7 @@ DATA_TYPES_REVERSE = {
21: 'SmallIntegerField',
23: 'IntegerField',
25: 'TextField',
701: 'FloatField',
869: 'IPAddressField',
1043: 'CharField',
1082: 'DateField',
@ -79,5 +80,5 @@ DATA_TYPES_REVERSE = {
1114: 'DateTimeField',
1184: 'DateTimeField',
1266: 'TimeField',
1700: 'FloatField',
1700: 'DecimalField',
}

View File

@ -17,6 +17,11 @@ except ImportError, e:
module = 'sqlite3'
raise ImproperlyConfigured, "Error loading %s module: %s" % (module, e)
try:
import decimal
except ImportError:
from django.utils import _decimal as decimal # for Python 2.3
DatabaseError = Database.DatabaseError
IntegrityError = Database.IntegrityError
@ -26,6 +31,8 @@ Database.register_converter("date", util.typecast_date)
Database.register_converter("datetime", util.typecast_timestamp)
Database.register_converter("timestamp", util.typecast_timestamp)
Database.register_converter("TIMESTAMP", util.typecast_timestamp)
Database.register_converter("decimal", util.typecast_decimal)
Database.register_adapter(decimal.Decimal, util.rev_typecast_decimal)
def utf8rowFactory(cursor, row):
def utf8(s):

View File

@ -8,9 +8,10 @@ DATA_TYPES = {
'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
'DateField': 'date',
'DateTimeField': 'datetime',
'DecimalField': 'decimal',
'FileField': 'varchar(100)',
'FilePathField': 'varchar(100)',
'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'FloatField': 'real',
'ImageField': 'varchar(100)',
'IntegerField': 'integer',
'IPAddressField': 'char(15)',

View File

@ -1,6 +1,11 @@
import datetime
from time import time
try:
import decimal
except ImportError:
from django.utils import _decimal as decimal # for Python 2.3
class CursorDebugWrapper(object):
def __init__(self, cursor, db):
self.cursor = cursor
@ -85,6 +90,11 @@ def typecast_boolean(s):
if not s: return False
return str(s)[0].lower() == 't'
def typecast_decimal(s):
if s is None:
return None
return decimal.Decimal(s)
###############################################
# Converters from Python to database (string) #
###############################################
@ -92,6 +102,11 @@ def typecast_boolean(s):
def rev_typecast_boolean(obj, d):
return obj and '1' or '0'
def rev_typecast_decimal(d):
if d is None:
return None
return str(d)
##################################################################################
# Helper functions for dictfetch* for databases that don't natively support them #
##################################################################################

View File

@ -10,6 +10,10 @@ from django.utils.itercompat import tee
from django.utils.text import capfirst
from django.utils.translation import gettext, gettext_lazy
import datetime, os, time
try:
import decimal
except ImportError:
from django.utils import _decimal as decimal # for Python 2.3
class NOT_PROVIDED:
pass
@ -570,6 +574,65 @@ class DateTimeField(DateField):
defaults.update(kwargs)
return super(DateTimeField, self).formfield(**defaults)
class DecimalField(Field):
empty_strings_allowed = False
def __init__(self, verbose_name=None, name=None, max_digits=None, decimal_places=None, **kwargs):
self.max_digits, self.decimal_places = max_digits, decimal_places
Field.__init__(self, verbose_name, name, **kwargs)
def to_python(self, value):
if value is None:
return value
try:
return decimal.Decimal(value)
except decimal.InvalidOperation:
raise validators.ValidationError, gettext("This value must be a decimal number.")
def _format(self, value):
if isinstance(value, basestring):
return value
else:
return self.format_number(value)
def format_number(self, value):
"""
Formats a number into a string with the requisite number of digits and
decimal places.
"""
num_chars = self.max_digits
# Allow for a decimal point
if self.decimal_places > 0:
num_chars += 1
# Allow for a minus sign
if value < 0:
num_chars += 1
return "%.*f" % (self.decimal_places, value)
def get_db_prep_save(self, value):
if value is not None:
value = self._format(value)
return super(DecimalField, self).get_db_prep_save(value)
def get_db_prep_lookup(self, lookup_type, value):
if lookup_type == 'range':
value = [self._format(v) for v in value]
else:
value = self._format(value)
return super(DecimalField, self).get_db_prep_lookup(lookup_type, value)
def get_manipulator_field_objs(self):
return [curry(oldforms.DecimalField, max_digits=self.max_digits, decimal_places=self.decimal_places)]
def formfield(self, **kwargs):
defaults = {
'max_digits': self.max_digits,
'decimal_places': self.decimal_places,
'form_class': forms.DecimalField,
}
defaults.update(kwargs)
return super(DecimalField, self).formfield(**defaults)
class EmailField(CharField):
def __init__(self, *args, **kwargs):
kwargs['maxlength'] = 75
@ -680,12 +743,14 @@ class FilePathField(Field):
class FloatField(Field):
empty_strings_allowed = False
def __init__(self, verbose_name=None, name=None, max_digits=None, decimal_places=None, **kwargs):
self.max_digits, self.decimal_places = max_digits, decimal_places
Field.__init__(self, verbose_name, name, **kwargs)
def get_manipulator_field_objs(self):
return [curry(oldforms.FloatField, max_digits=self.max_digits, decimal_places=self.decimal_places)]
return [oldforms.FloatField]
def formfield(self, **kwargs):
defaults = {'form_class': forms.FloatField}
defaults.update(kwargs)
return super(FloatField, self).formfield(**defaults)
class ImageField(FileField):
def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, **kwargs):

View File

@ -19,7 +19,7 @@ __all__ = (
'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField',
'RegexField', 'EmailField', 'URLField', 'BooleanField',
'ChoiceField', 'NullBooleanField', 'MultipleChoiceField',
'ComboField', 'MultiValueField',
'ComboField', 'MultiValueField', 'FloatField', 'DecimalField',
'SplitDateTimeField',
)
@ -31,6 +31,11 @@ try:
except NameError:
from sets import Set as set # Python 2.3 fallback
try:
from decimal import Decimal
except ImportError:
from django.utils._decimal import Decimal # Python 2.3 fallback
class Field(object):
widget = TextInput # Default widget to use when rendering this type of Field.
hidden_widget = HiddenInput # Default widget to use when rendering this as "hidden".
@ -134,6 +139,67 @@ class IntegerField(Field):
raise ValidationError(gettext(u'Ensure this value is greater than or equal to %s.') % self.min_value)
return value
class FloatField(Field):
def __init__(self, max_value=None, min_value=None, *args, **kwargs):
self.max_value, self.min_value = max_value, min_value
Field.__init__(self, *args, **kwargs)
def clean(self, value):
"""
Validates that float() can be called on the input. Returns a float.
Returns None for empty values.
"""
super(FloatField, self).clean(value)
if not self.required and value in EMPTY_VALUES:
return None
try:
value = float(value)
except (ValueError, TypeError):
raise ValidationError(gettext('Enter a number.'))
if self.max_value is not None and value > self.max_value:
raise ValidationError(gettext('Ensure this value is less than or equal to %s.') % self.max_value)
if self.min_value is not None and value < self.min_value:
raise ValidationError(gettext('Ensure this value is greater than or equal to %s.') % self.min_value)
return value
decimal_re = re.compile(r'^-?(?P<digits>\d+)(\.(?P<decimals>\d+))?$')
class DecimalField(Field):
def __init__(self, max_value=None, min_value=None, max_digits=None, decimal_places=None, *args, **kwargs):
self.max_value, self.min_value = max_value, min_value
self.max_digits, self.decimal_places = max_digits, decimal_places
Field.__init__(self, *args, **kwargs)
def clean(self, value):
"""
Validates that the input is a decimal number. Returns a Decimal
instance. Returns None for empty values. Ensures that there are no more
than max_digits in the number, and no more than decimal_places digits
after the decimal point.
"""
super(DecimalField, self).clean(value)
if not self.required and value in EMPTY_VALUES:
return None
value = value.strip()
match = decimal_re.search(value)
if not match:
raise ValidationError(gettext('Enter a number.'))
else:
value = Decimal(value)
digits = len(match.group('digits') or '')
decimals = len(match.group('decimals') or '')
if self.max_value is not None and value > self.max_value:
raise ValidationError(gettext('Ensure this value is less than or equal to %s.') % self.max_value)
if self.min_value is not None and value < self.min_value:
raise ValidationError(gettext('Ensure this value is greater than or equal to %s.') % self.min_value)
if self.max_digits is not None and (digits + decimals) > self.max_digits:
raise ValidationError(gettext('Ensure that there are no more than %s digits in total.') % self.max_digits)
if self.decimal_places is not None and decimals > self.decimal_places:
raise ValidationError(gettext('Ensure that there are no more than %s decimal places.') % self.decimal_places)
if self.max_digits is not None and self.decimal_places is not None and digits > (self.max_digits - self.decimal_places):
raise ValidationError(gettext('Ensure that there are no more than %s digits before the decimal point.') % (self.max_digits - self.decimal_places))
return value
DEFAULT_DATE_INPUT_FORMATS = (
'%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06'
'%b %d %Y', '%b %d, %Y', # 'Oct 25 2006', 'Oct 25, 2006'

View File

@ -750,14 +750,27 @@ class PositiveSmallIntegerField(IntegerField):
raise validators.CriticalValidationError, gettext("Enter a whole number between 0 and 32,767.")
class FloatField(TextField):
def __init__(self, field_name, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
validator_list = [validators.isValidFloat] + validator_list
TextField.__init__(self, field_name, is_required=is_required, validator_list=validator_list)
def html2python(data):
if data == '' or data is None:
return None
return float(data)
html2python = staticmethod(html2python)
class DecimalField(TextField):
def __init__(self, field_name, max_digits, decimal_places, is_required=False, validator_list=None):
if validator_list is None: validator_list = []
self.max_digits, self.decimal_places = max_digits, decimal_places
validator_list = [self.isValidFloat] + validator_list
TextField.__init__(self, field_name, max_digits+2, max_digits+2, is_required, validator_list)
validator_list = [self.isValidDecimal] + validator_list
# Initialise the TextField, making sure it's large enough to fit the number with a - sign and a decimal point.
super(DecimalField, self).__init__(field_name, max_digits+2, max_digits+2, is_required, validator_list)
def isValidFloat(self, field_data, all_data):
v = validators.IsValidFloat(self.max_digits, self.decimal_places)
def isValidDecimal(self, field_data, all_data):
v = validators.IsValidDecimal(self.max_digits, self.decimal_places)
try:
v(field_data, all_data)
except validators.ValidationError, e:
@ -766,7 +779,14 @@ class FloatField(TextField):
def html2python(data):
if data == '' or data is None:
return None
return float(data)
try:
import decimal
except ImportError:
from django.utils import decimal
try:
return decimal.Decimal(data)
except decimal.InvalidOperation, e:
raise ValueError, e
html2python = staticmethod(html2python)
####################

3079
django/utils/_decimal.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -567,6 +567,7 @@ check for the given property:
* isValidANSIDate
* isValidANSITime
* isValidEmail
* isValidFloat
* isValidImage
* isValidImageURL
* isValidPhone
@ -664,10 +665,10 @@ fails. If no message is passed in, a default message is used.
Takes an integer argument and when called as a validator, checks that the
field being validated is a power of the integer.
``IsValidFloat``
``IsValidDecimal``
Takes a maximum number of digits and number of decimal places (in that
order) and validates whether the field is a float with less than the
maximum number of digits and decimal place.
order) and validates whether the field is a decimal with no more than the
maximum number of digits and decimal places.
``MatchesRegularExpression``
Takes a regular expression (a string) as a parameter and validates the

View File

@ -184,6 +184,35 @@ A date and time field. Takes the same extra options as ``DateField``.
The admin represents this as two ``<input type="text">`` fields, with
JavaScript shortcuts.
``DecimalField``
~~~~~~~~~~~~~~~~
**New in Django development version**
A fixed-precision decimal number, represented in Python by a ``Decimal`` instance.
Has two **required** arguments:
====================== ===================================================
Argument Description
====================== ===================================================
``max_digits`` The maximum number of digits allowed in the number.
``decimal_places`` The number of decimal places to store with the
number.
====================== ===================================================
For example, to store numbers up to 999 with a resolution of 2 decimal places,
you'd use::
models.DecimalField(..., max_digits=5, decimal_places=2)
And to store numbers up to approximately one billion with a resolution of 10
decimal places::
models.DecimalField(..., max_digits=19, decimal_places=10)
The admin represents this as an ``<input type="text">`` (a single-line input).
``EmailField``
~~~~~~~~~~~~~~
@ -290,29 +319,17 @@ because the ``match`` applies to the base filename (``foo.gif`` and
``FloatField``
~~~~~~~~~~~~~~
A floating-point number. Has two **required** arguments:
**Changed in Django development version**
====================== ===================================================
Argument Description
====================== ===================================================
``max_digits`` The maximum number of digits allowed in the number.
``decimal_places`` The number of decimal places to store with the
number.
====================== ===================================================
For example, to store numbers up to 999 with a resolution of 2 decimal places,
you'd use::
models.FloatField(..., max_digits=5, decimal_places=2)
And to store numbers up to approximately one billion with a resolution of 10
decimal places::
models.FloatField(..., max_digits=19, decimal_places=10)
A floating-point number represented in Python by a ``float`` instance.
The admin represents this as an ``<input type="text">`` (a single-line input).
**NOTE:** The semantics of ``FloatField`` have changed in the Django
development version. See the `Django 0.96 documentation`_ for the old behavior.
.. _Django 0.96 documentation: http://www.djangoproject.com/documentation/0.96/model-api/#floatfield
``ImageField``
~~~~~~~~~~~~~~

View File

@ -1253,10 +1253,11 @@ the full list of conversions:
``CommaSeparatedIntegerField`` ``CharField``
``DateField`` ``DateField``
``DateTimeField`` ``DateTimeField``
``DecimalField`` ``DecimalField``
``EmailField`` ``EmailField``
``FileField`` ``CharField``
``FilePathField`` ``CharField``
``FloatField`` ``CharField``
``FloatField`` ``FloatField``
``ForeignKey`` ``ModelChoiceField`` (see below)
``ImageField`` ``CharField``
``IntegerField`` ``IntegerField``
@ -1281,6 +1282,11 @@ the full list of conversions:
``XMLField`` ``CharField`` with ``widget=Textarea``
=============================== ========================================
.. note::
The ``FloatField`` form field and ``DecimalField`` model and form fields
are new in the development version.
As you might expect, the ``ForeignKey`` and ``ManyToManyField`` model field
types are special cases:

View File

@ -320,7 +320,7 @@ method a ``short_description`` attribute::
Let's add another improvement to the Poll change list page: Filters. Add the
following line to ``Poll.admin``::
following line to ``Poll.Admin``::
list_filter = ['pub_date']

View File

@ -8,7 +8,7 @@ from django.db import models
class FieldErrors(models.Model):
charfield = models.CharField()
floatfield = models.FloatField()
decimalfield = models.DecimalField()
filefield = models.FileField()
prepopulate = models.CharField(maxlength=10, prepopulate_from='bad')
choices = models.CharField(maxlength=10, choices='bad')
@ -108,8 +108,8 @@ class Car(models.Model):
model = models.ForeignKey(Model)
model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "maxlength" attribute.
invalid_models.fielderrors: "floatfield": FloatFields require a "decimal_places" attribute.
invalid_models.fielderrors: "floatfield": FloatFields require a "max_digits" attribute.
invalid_models.fielderrors: "decimalfield": DecimalFields require a "decimal_places" attribute.
invalid_models.fielderrors: "decimalfield": DecimalFields require a "max_digits" attribute.
invalid_models.fielderrors: "filefield": FileFields require an "upload_to" attribute.
invalid_models.fielderrors: "prepopulate": prepopulate_from should be a list or tuple.
invalid_models.fielderrors: "choices": "choices" should be iterable (e.g., a tuple or list).

View File

@ -8,6 +8,10 @@ form_tests = r"""
>>> import datetime
>>> import time
>>> import re
>>> try:
... from decimal import Decimal
... except ImportError:
... from django.utils._decimal import Decimal
###########
# Widgets #
@ -1047,6 +1051,133 @@ Traceback (most recent call last):
...
ValidationError: [u'Ensure this value is less than or equal to 20.']
# FloatField ##################################################################
>>> f = FloatField()
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'This field is required.']
>>> f.clean(None)
Traceback (most recent call last):
...
ValidationError: [u'This field is required.']
>>> f.clean('1')
1.0
>>> isinstance(f.clean('1'), float)
True
>>> f.clean('23')
23.0
>>> f.clean('3.14')
3.1400000000000001
>>> f.clean('a')
Traceback (most recent call last):
...
ValidationError: [u'Enter a number.']
>>> f.clean('1.0 ')
1.0
>>> f.clean(' 1.0')
1.0
>>> f.clean(' 1.0 ')
1.0
>>> f.clean('1.0a')
Traceback (most recent call last):
...
ValidationError: [u'Enter a number.']
>>> f = FloatField(required=False)
>>> f.clean('')
>>> f.clean(None)
>>> f.clean('1')
1.0
FloatField accepts min_value and max_value just like IntegerField:
>>> f = FloatField(max_value=1.5, min_value=0.5)
>>> f.clean('1.6')
Traceback (most recent call last):
...
ValidationError: [u'Ensure this value is less than or equal to 1.5.']
>>> f.clean('0.4')
Traceback (most recent call last):
...
ValidationError: [u'Ensure this value is greater than or equal to 0.5.']
>>> f.clean('1.5')
1.5
>>> f.clean('0.5')
0.5
# DecimalField ################################################################
>>> f = DecimalField(max_digits=4, decimal_places=2)
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'This field is required.']
>>> f.clean(None)
Traceback (most recent call last):
...
ValidationError: [u'This field is required.']
>>> f.clean('1')
Decimal("1")
>>> isinstance(f.clean('1'), Decimal)
True
>>> f.clean('23')
Decimal("23")
>>> f.clean('3.14')
Decimal("3.14")
>>> f.clean('a')
Traceback (most recent call last):
...
ValidationError: [u'Enter a number.']
>>> f.clean('1.0 ')
Decimal("1.0")
>>> f.clean(' 1.0')
Decimal("1.0")
>>> f.clean(' 1.0 ')
Decimal("1.0")
>>> f.clean('1.0a')
Traceback (most recent call last):
...
ValidationError: [u'Enter a number.']
>>> f.clean('123.45')
Traceback (most recent call last):
...
ValidationError: [u'Ensure that there are no more than 4 digits in total.']
>>> f.clean('1.234')
Traceback (most recent call last):
...
ValidationError: [u'Ensure that there are no more than 2 decimal places.']
>>> f.clean('123.4')
Traceback (most recent call last):
...
ValidationError: [u'Ensure that there are no more than 2 digits before the decimal point.']
>>> f = DecimalField(max_digits=4, decimal_places=2, required=False)
>>> f.clean('')
>>> f.clean(None)
>>> f.clean('1')
Decimal("1")
DecimalField accepts min_value and max_value just like IntegerField:
>>> f = DecimalField(max_digits=4, decimal_places=2, max_value=Decimal('1.5'), min_value=Decimal('0.5'))
>>> f.clean('1.6')
Traceback (most recent call last):
...
ValidationError: [u'Ensure this value is less than or equal to 1.5.']
>>> f.clean('0.4')
Traceback (most recent call last):
...
ValidationError: [u'Ensure this value is greater than or equal to 0.5.']
>>> f.clean('1.5')
Decimal("1.5")
>>> f.clean('0.5')
Decimal("0.5")
# DateField ###################################################################
>>> import datetime

View File

@ -24,6 +24,9 @@ class DateData(models.Model):
class DateTimeData(models.Model):
data = models.DateTimeField(null=True)
class DecimalData(models.Model):
data = models.DecimalField(null=True, decimal_places=3, max_digits=5)
class EmailData(models.Model):
data = models.EmailField(null=True)
@ -34,7 +37,7 @@ class FilePathData(models.Model):
data = models.FilePathField(null=True)
class FloatData(models.Model):
data = models.FloatField(null=True, decimal_places=3, max_digits=5)
data = models.FloatField(null=True)
class IntegerData(models.Model):
data = models.IntegerField(null=True)
@ -145,6 +148,9 @@ class CharPKData(models.Model):
# class DateTimePKData(models.Model):
# data = models.DateTimeField(primary_key=True)
class DecimalPKData(models.Model):
data = models.DecimalField(primary_key=True, decimal_places=3, max_digits=5)
class EmailPKData(models.Model):
data = models.EmailField(primary_key=True)
@ -155,7 +161,7 @@ class FilePathPKData(models.Model):
data = models.FilePathField(primary_key=True)
class FloatPKData(models.Model):
data = models.FloatField(primary_key=True, decimal_places=3, max_digits=5)
data = models.FloatField(primary_key=True)
class IntegerPKData(models.Model):
data = models.IntegerField(primary_key=True)

View File

@ -16,6 +16,10 @@ from django.db import transaction
from django.core import management
from models import *
try:
import decimal
except ImportError:
from django.utils import _decimal as decimal
# A set of functions that can be used to recreate
# test data objects of various kinds
@ -115,10 +119,14 @@ test_data = [
(data_obj, 51, FileData, None),
(data_obj, 60, FilePathData, "/foo/bar/whiz.txt"),
(data_obj, 61, FilePathData, None),
(data_obj, 70, FloatData, 12.345),
(data_obj, 71, FloatData, -12.345),
(data_obj, 72, FloatData, 0.0),
(data_obj, 73, FloatData, None),
(data_obj, 70, DecimalData, decimal.Decimal('12.345')),
(data_obj, 71, DecimalData, decimal.Decimal('-12.345')),
(data_obj, 72, DecimalData, decimal.Decimal('0.0')),
(data_obj, 73, DecimalData, None),
(data_obj, 74, FloatData, 12.345),
(data_obj, 75, FloatData, -12.345),
(data_obj, 76, FloatData, 0.0),
(data_obj, 77, FloatData, None),
(data_obj, 80, IntegerData, 123456789),
(data_obj, 81, IntegerData, -123456789),
(data_obj, 82, IntegerData, 0),
@ -201,9 +209,12 @@ The end."""),
(pk_obj, 640, EmailPKData, "hovercraft@example.com"),
(pk_obj, 650, FilePKData, 'file:///foo/bar/whiz.txt'),
(pk_obj, 660, FilePathPKData, "/foo/bar/whiz.txt"),
(pk_obj, 670, FloatPKData, 12.345),
(pk_obj, 671, FloatPKData, -12.345),
(pk_obj, 672, FloatPKData, 0.0),
(pk_obj, 670, DecimalPKData, decimal.Decimal('12.345')),
(pk_obj, 671, DecimalPKData, decimal.Decimal('-12.345')),
(pk_obj, 672, DecimalPKData, decimal.Decimal('0.0')),
(pk_obj, 673, FloatPKData, 12.345),
(pk_obj, 674, FloatPKData, -12.345),
(pk_obj, 675, FloatPKData, 0.0),
(pk_obj, 680, IntegerPKData, 123456789),
(pk_obj, 681, IntegerPKData, -123456789),
(pk_obj, 682, IntegerPKData, 0),