Add time format validation
review342002
This commit is contained in:
1 parent
3a42c2ef49
commit
3ebda5c8ee
8 files changed
+108
-5
No files matched your search
@@ -1,3 +1,4 @@
|
||||
* Add time format validation
|
||||
* Remove ModelSQL.default_sequence
|
||||
|
||||
Version 2.4.0 - 2012-04-23
|
||||
|
||||
@@ -272,17 +272,27 @@ A date, represented in Python by a ``datetime.date`` instance.
|
||||
DateTime
|
||||
--------
|
||||
|
||||
.. class:: DateTime(string[, \**options])
|
||||
.. class:: DateTime(string[, format, \**options])
|
||||
|
||||
A date and time, represented in Python by a ``datetime.datetime`` instance.
|
||||
|
||||
.. attribute:: DateTime.format
|
||||
|
||||
A string format as used by strftime. This format will be used to display
|
||||
the time part of the field. The default value is `%H:%M:%S`.
|
||||
The value can be replaced by a :class:`~trytond.pyson.PYSON` statement.
|
||||
|
||||
Time
|
||||
----
|
||||
|
||||
.. class:: Time(string[, \**options])
|
||||
.. class:: Time(string[, format, \**options])
|
||||
|
||||
A time, represented in Python by a ``datetime.time`` instance.
|
||||
|
||||
.. attribute:: Time.format
|
||||
|
||||
Same as :attr:`DateTime.format`
|
||||
|
||||
Binary
|
||||
------
|
||||
|
||||
|
||||
@@ -177,6 +177,15 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<field name="module">ir</field>
|
||||
<field name="fuzzy" eval="False"/>
|
||||
</record>
|
||||
<record model="ir.translation" id="translation_time_format_validation_record">
|
||||
<field name="name">time_format_validation_record</field>
|
||||
<field name="lang">en_US</field>
|
||||
<field name="type">error</field>
|
||||
<field name="src">The time value of field "%s" on "%s" is not valid.</field>
|
||||
<field name="value">The time value of field "%s" on "%s" is not valid.</field>
|
||||
<field name="module">ir</field>
|
||||
<field name="fuzzy" eval="False"/>
|
||||
</record>
|
||||
<record model="ir.translation" id="translation_access_error">
|
||||
<field name="name">access_error</field>
|
||||
<field name="lang">en_US</field>
|
||||
|
||||
@@ -17,8 +17,24 @@ class DateTime(Field):
|
||||
'''
|
||||
_type = 'datetime'
|
||||
|
||||
def __init__(self, string='', format='%H:%M:%S', help='', required=False,
|
||||
readonly=False, domain=None, states=None, select=False,
|
||||
on_change=None, on_change_with=None, depends=None,
|
||||
order_field=None, context=None, loading='eager'):
|
||||
'''
|
||||
:param format: The validation format as used by strftime.
|
||||
'''
|
||||
super(DateTime, self).__init__(string=string, help=help,
|
||||
required=required, readonly=readonly, domain=domain, states=states,
|
||||
select=select, on_change=on_change, on_change_with=on_change_with,
|
||||
depends=depends, order_field=order_field, context=context,
|
||||
loading=loading)
|
||||
self.format = format
|
||||
|
||||
class Time(Field):
|
||||
__init__.__doc__ += Field.__init__.__doc__
|
||||
|
||||
|
||||
class Time(DateTime):
|
||||
'''
|
||||
Define a time field (``time``).
|
||||
'''
|
||||
|
||||
@@ -554,10 +554,12 @@ class Model(WarningErrorMixin, URLMixin):
|
||||
and hasattr(self._columns[field], 'field'):
|
||||
res[field]['relation_field'] = copy.copy(
|
||||
self._columns[field].field)
|
||||
if res[field]['type'] in ('datetime', 'time'):
|
||||
res[field]['format'] = copy.copy(self._columns[field].format)
|
||||
|
||||
# convert attributes into pyson
|
||||
for attr in ('states', 'domain', 'context', 'digits',
|
||||
'add_remove'):
|
||||
'add_remove', 'format'):
|
||||
if attr in res[field]:
|
||||
res[field][attr] = encoder.encode(res[field][attr])
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ from trytond.model import fields
|
||||
from trytond.model.browse import BrowseRecordList, BrowseRecord, \
|
||||
BrowseRecordNull
|
||||
from trytond.model.browse import EvalEnvironment
|
||||
from trytond.tools import safe_eval, reduce_domain
|
||||
from trytond.tools import safe_eval, reduce_domain, datetime_strftime
|
||||
from trytond.pyson import PYSONEncoder, PYSONDecoder, PYSON
|
||||
from trytond.const import OPERATORS, RECORD_CACHE_SIZE
|
||||
from trytond.transaction import Transaction
|
||||
@@ -1132,6 +1132,35 @@ class ModelStorage(Model):
|
||||
digits_test(record[field_name], field.digits,
|
||||
field_name)
|
||||
|
||||
def format_test(value, format, field_name):
|
||||
if not value:
|
||||
return
|
||||
if not isinstance(value, datetime.time):
|
||||
value = value.time()
|
||||
if value != datetime.datetime.strptime(
|
||||
value.strftime(format), format).time():
|
||||
self.raise_user_error('time_format_validation_record',
|
||||
error_args=self._get_error_args(field_name))
|
||||
|
||||
# validate time format
|
||||
if (field._type in ('datetime', 'time')
|
||||
and field_name not in ('create_date', 'write_date')):
|
||||
if is_pyson(field.format):
|
||||
pyson_format = PYSONDecoder().encode(field.format)
|
||||
for record in records:
|
||||
env = EvalEnvironment(record, self)
|
||||
env.update(Transaction().context)
|
||||
env['current_date'] = datetime.datetime.today()
|
||||
env['time'] = time
|
||||
env['context'] = Transaction().context
|
||||
env['active_id'] = record.id
|
||||
format = PYSONDecoder(env).decode(pyson_format)
|
||||
format_test(record[field_name], format, field_name)
|
||||
else:
|
||||
for record in records:
|
||||
format_test(record[field_name], field.format,
|
||||
field_name)
|
||||
|
||||
def _clean_defaults(self, defaults):
|
||||
pool = Pool()
|
||||
vals = {}
|
||||
|
||||
@@ -356,6 +356,15 @@ class DateTimeRequired(ModelSQL):
|
||||
DateTimeRequired()
|
||||
|
||||
|
||||
class DateTimeFormat(ModelSQL):
|
||||
'DateTime Format'
|
||||
_name = 'test.datetime_format'
|
||||
_description = __doc__
|
||||
datetime = fields.DateTime(string='DateTime', format='%H:%M')
|
||||
|
||||
DateTimeFormat()
|
||||
|
||||
|
||||
class Time(ModelSQL):
|
||||
'Time'
|
||||
_name = 'test.time'
|
||||
@@ -386,6 +395,15 @@ class TimeRequired(ModelSQL):
|
||||
TimeRequired()
|
||||
|
||||
|
||||
class TimeFormat(ModelSQL):
|
||||
'Time Format'
|
||||
_name = 'test.time_format'
|
||||
_description = __doc__
|
||||
time = fields.Time(string='Time', format='%H:%M')
|
||||
|
||||
TimeFormat()
|
||||
|
||||
|
||||
class One2One(ModelSQL):
|
||||
'One2One'
|
||||
_name = 'test.one2one'
|
||||
|
||||
@@ -65,10 +65,12 @@ class FieldsTestCase(unittest.TestCase):
|
||||
self.datetime = POOL.get('test.datetime')
|
||||
self.datetime_default = POOL.get('test.datetime_default')
|
||||
self.datetime_required = POOL.get('test.datetime_required')
|
||||
self.datetime_format = POOL.get('test.datetime_format')
|
||||
|
||||
self.time = POOL.get('test.time')
|
||||
self.time_default = POOL.get('test.time_default')
|
||||
self.time_required = POOL.get('test.time_required')
|
||||
self.time_format = POOL.get('test.time_format')
|
||||
|
||||
self.one2one = POOL.get('test.one2one')
|
||||
self.one2one_target = POOL.get('test.one2one.target')
|
||||
@@ -2059,6 +2061,14 @@ class FieldsTestCase(unittest.TestCase):
|
||||
datetime9 = self.datetime.read(datetime9_id, ['datetime'])
|
||||
self.assert_(datetime9['datetime'] == today)
|
||||
|
||||
# Test format
|
||||
self.assert_(self.datetime_format.create({
|
||||
'datetime': datetime.datetime(2009, 1, 1, 12, 30),
|
||||
}))
|
||||
self.failUnlessRaises(Exception, self.datetime_format.create, {
|
||||
'datetime': datetime.datetime(2009, 1, 1, 12, 30, 25),
|
||||
})
|
||||
|
||||
transaction.cursor.rollback()
|
||||
|
||||
def test0100time(self):
|
||||
@@ -2312,6 +2322,14 @@ class FieldsTestCase(unittest.TestCase):
|
||||
time9 = self.time.read(time9_id, ['time'])
|
||||
self.assert_(time9['time'] == evening)
|
||||
|
||||
# Test format
|
||||
self.assert_(self.time_format.create({
|
||||
'time': datetime.time(12, 30),
|
||||
}))
|
||||
self.failUnlessRaises(Exception, self.time_format.create, {
|
||||
'time': datetime.time(12, 30, 25),
|
||||
})
|
||||
|
||||
transaction.cursor.rollback()
|
||||
|
||||
def test0110one2one(self):
|
||||
|
||||
Reference in new issue
Block a user