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:
parent
3eab964332
commit
659d99b7af
2
AUTHORS
2
AUTHORS
@ -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
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -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
|
||||
|
Binary file not shown.
@ -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."
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
19
django/contrib/sessions/tests.py
Normal file
19
django/contrib/sessions/tests.py
Normal 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()
|
@ -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):
|
||||
|
@ -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
|
||||
|
||||
|
@ -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):
|
||||
"""
|
||||
|
@ -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)',
|
||||
|
@ -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
|
||||
|
@ -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)',
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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)',
|
||||
|
@ -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',
|
||||
|
@ -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)',
|
||||
|
@ -46,5 +46,5 @@ DATA_TYPES_REVERSE = {
|
||||
1114: 'DateTimeField',
|
||||
1184: 'DateTimeField',
|
||||
1266: 'TimeField',
|
||||
1700: 'FloatField',
|
||||
1700: 'DecimalField',
|
||||
}
|
||||
|
@ -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',
|
||||
|
@ -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',
|
||||
|
@ -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',
|
||||
}
|
||||
|
@ -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',
|
||||
}
|
||||
|
@ -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):
|
||||
|
@ -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)',
|
||||
|
@ -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 #
|
||||
##################################################################################
|
||||
|
@ -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):
|
||||
|
@ -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'
|
||||
|
@ -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
3079
django/utils/_decimal.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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``
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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']
|
||||
|
||||
|
@ -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).
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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),
|
||||
|
Loading…
x
Reference in New Issue
Block a user