8
8
import warnings
9
9
10
10
# Django
11
+ import django
11
12
try :
12
13
from django .core import checks
13
14
except ImportError : # pragma: no cover
14
15
pass
15
16
from django .core .exceptions import ValidationError
16
- from django .db . models import SubfieldBase
17
+ from django .db import models
17
18
from django .db .models .fields import DateTimeField , CharField
18
19
from django .utils .six import with_metaclass
19
20
from django .utils .timezone import get_default_timezone , is_naive , make_aware
22
23
# App
23
24
from timezone_utils import forms
24
25
26
+
27
+ TimeZoneFieldBase = type if django .VERSION >= (1 , 8 ) else models .SubfieldBase
28
+
25
29
__all__ = ('TimeZoneField' , 'LinkedTZDateTimeField' )
26
30
27
31
28
32
# ==============================================================================
29
33
# MODEL FIELDS
30
34
# ==============================================================================
31
- class TimeZoneField (with_metaclass (SubfieldBase , CharField )):
35
+ class TimeZoneField (with_metaclass (TimeZoneFieldBase , CharField )):
32
36
# Enforce the minimum length of max_length to be the length of the longest
33
37
# pytz timezone string
34
38
MIN_LENGTH = max (map (len , pytz .all_timezones ))
@@ -58,16 +62,43 @@ def __init__(self, *args, **kwargs):
58
62
59
63
super (TimeZoneField , self ).__init__ (* args , ** kwargs )
60
64
65
+ def validate (self , value , model_instance ):
66
+ """
67
+ Validates value and throws ValidationError. Subclasses should override
68
+ this to provide validation logic.
69
+ """
70
+ super (TimeZoneField , self ).validate (
71
+ value = self .get_prep_value (value ),
72
+ model_instance = model_instance
73
+ )
74
+
75
+ # Insure the value is can be converted to a timezone
76
+ self .to_python (value )
77
+
78
+ def run_validators (self , value ):
79
+ super (TimeZoneField , self ).run_validators (self .get_prep_value (value ))
80
+
61
81
def get_prep_value (self , value ):
62
82
"""Converts timezone instances to strings for db storage."""
83
+ value = super (TimeZoneField , self ).get_prep_value (value )
63
84
64
85
if isinstance (value , tzinfo ):
65
86
return value .zone
87
+
88
+ return value
89
+
90
+ def from_db_value (self , value , expression , connection , context ): # noqa
91
+ """
92
+ Converts a value as returned by the database to a Python object. It is
93
+ the reverse of get_prep_value(). - New in Django 1.8
94
+ """
95
+ if value :
96
+ value = self .to_python (value )
97
+
66
98
return value
67
99
68
100
def to_python (self , value ):
69
101
"""Returns a datetime.tzinfo instance for the value."""
70
-
71
102
value = super (TimeZoneField , self ).to_python (value )
72
103
73
104
if not value :
@@ -190,14 +221,19 @@ def _check_choices_attribute(self): # pragma: no cover
190
221
return []
191
222
192
223
193
- class LinkedTZDateTimeField (with_metaclass (SubfieldBase , DateTimeField )):
224
+ class LinkedTZDateTimeField (with_metaclass (TimeZoneFieldBase , DateTimeField )):
194
225
def __init__ (self , * args , ** kwargs ):
195
226
self .populate_from = kwargs .pop ('populate_from' , None )
196
227
self .time_override = kwargs .pop ('time_override' , None )
197
228
self .timezone = get_default_timezone ()
198
229
199
230
super (LinkedTZDateTimeField , self ).__init__ (* args , ** kwargs )
200
231
232
+ def from_db_value (self , value , expression , connection , context ): # noqa
233
+ if value :
234
+ value = self .to_python (value )
235
+ return value
236
+
201
237
def to_python (self , value ):
202
238
"""Convert the value to the appropriate timezone."""
203
239
@@ -206,9 +242,6 @@ def to_python(self, value):
206
242
if not value :
207
243
return value
208
244
209
- if is_naive (value ):
210
- return make_aware (value = value , timezone = self .timezone )
211
-
212
245
return value .astimezone (self .timezone )
213
246
214
247
def pre_save (self , model_instance , add ):
@@ -315,6 +348,9 @@ def _convert_value(self, value, model_instance, add):
315
348
if self .populate_from is not None :
316
349
tz = self ._get_populate_from (model_instance )
317
350
351
+ if is_naive (value ):
352
+ value = make_aware (value = value , timezone = tz )
353
+
318
354
# Convert the value to a datetime object in the correct timezone. This
319
355
# insures that we will have the correct date if we are performing a time
320
356
# override below.
0 commit comments