Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
D
django-rest-framework
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
django-rest-framework
Commits
6284bcea
Commit
6284bcea
authored
Sep 24, 2015
by
Tom Christie
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3363 from tomchristie/dont-access-settings-on-import
Access settings lazily, not at module import.
parents
509c54de
f9e53091
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
78 additions
and
50 deletions
+78
-50
rest_framework/fields.py
+65
-45
rest_framework/serializers.py
+4
-1
rest_framework/settings.py
+9
-4
No files found.
rest_framework/fields.py
View file @
6284bcea
...
@@ -885,12 +885,11 @@ class DecimalField(Field):
...
@@ -885,12 +885,11 @@ class DecimalField(Field):
}
}
MAX_STRING_LENGTH
=
1000
# Guard against malicious string inputs.
MAX_STRING_LENGTH
=
1000
# Guard against malicious string inputs.
coerce_to_string
=
api_settings
.
COERCE_DECIMAL_TO_STRING
def
__init__
(
self
,
max_digits
,
decimal_places
,
coerce_to_string
=
None
,
max_value
=
None
,
min_value
=
None
,
**
kwargs
):
def
__init__
(
self
,
max_digits
,
decimal_places
,
coerce_to_string
=
None
,
max_value
=
None
,
min_value
=
None
,
**
kwargs
):
self
.
max_digits
=
max_digits
self
.
max_digits
=
max_digits
self
.
decimal_places
=
decimal_places
self
.
decimal_places
=
decimal_places
self
.
coerce_to_string
=
coerce_to_string
if
(
coerce_to_string
is
not
None
)
else
self
.
coerce_to_string
if
coerce_to_string
is
not
None
:
self
.
coerce_to_string
=
coerce_to_string
self
.
max_value
=
max_value
self
.
max_value
=
max_value
self
.
min_value
=
min_value
self
.
min_value
=
min_value
...
@@ -970,12 +969,14 @@ class DecimalField(Field):
...
@@ -970,12 +969,14 @@ class DecimalField(Field):
return
value
return
value
def
to_representation
(
self
,
value
):
def
to_representation
(
self
,
value
):
coerce_to_string
=
getattr
(
self
,
'coerce_to_string'
,
api_settings
.
COERCE_DECIMAL_TO_STRING
)
if
not
isinstance
(
value
,
decimal
.
Decimal
):
if
not
isinstance
(
value
,
decimal
.
Decimal
):
value
=
decimal
.
Decimal
(
six
.
text_type
(
value
)
.
strip
())
value
=
decimal
.
Decimal
(
six
.
text_type
(
value
)
.
strip
())
quantized
=
self
.
quantize
(
value
)
quantized
=
self
.
quantize
(
value
)
if
not
self
.
coerce_to_string
:
if
not
coerce_to_string
:
return
quantized
return
quantized
return
'{0:f}'
.
format
(
quantized
)
return
'{0:f}'
.
format
(
quantized
)
...
@@ -997,15 +998,15 @@ class DateTimeField(Field):
...
@@ -997,15 +998,15 @@ class DateTimeField(Field):
'invalid'
:
_
(
'Datetime has wrong format. Use one of these formats instead: {format}.'
),
'invalid'
:
_
(
'Datetime has wrong format. Use one of these formats instead: {format}.'
),
'date'
:
_
(
'Expected a datetime but got a date.'
),
'date'
:
_
(
'Expected a datetime but got a date.'
),
}
}
format
=
api_settings
.
DATETIME_FORMAT
input_formats
=
api_settings
.
DATETIME_INPUT_FORMATS
default_timezone
=
timezone
.
get_default_timezone
()
if
settings
.
USE_TZ
else
None
datetime_parser
=
datetime
.
datetime
.
strptime
datetime_parser
=
datetime
.
datetime
.
strptime
def
__init__
(
self
,
format
=
empty
,
input_formats
=
None
,
default_timezone
=
None
,
*
args
,
**
kwargs
):
def
__init__
(
self
,
format
=
empty
,
input_formats
=
None
,
default_timezone
=
None
,
*
args
,
**
kwargs
):
self
.
format
=
format
if
format
is
not
empty
else
self
.
format
if
format
is
not
empty
:
self
.
input_formats
=
input_formats
if
input_formats
is
not
None
else
self
.
input_formats
self
.
format
=
format
self
.
default_timezone
=
default_timezone
if
default_timezone
is
not
None
else
self
.
default_timezone
if
input_formats
is
not
None
:
self
.
input_formats
=
input_formats
if
default_timezone
is
not
None
:
self
.
timezone
=
default_timezone
super
(
DateTimeField
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
super
(
DateTimeField
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
def
enforce_timezone
(
self
,
value
):
def
enforce_timezone
(
self
,
value
):
...
@@ -1013,21 +1014,28 @@ class DateTimeField(Field):
...
@@ -1013,21 +1014,28 @@ class DateTimeField(Field):
When `self.default_timezone` is `None`, always return naive datetimes.
When `self.default_timezone` is `None`, always return naive datetimes.
When `self.default_timezone` is not `None`, always return aware datetimes.
When `self.default_timezone` is not `None`, always return aware datetimes.
"""
"""
if
(
self
.
default_timezone
is
not
None
)
and
not
timezone
.
is_aware
(
value
):
field_timezone
=
getattr
(
self
,
'timezone'
,
self
.
default_timezone
())
return
timezone
.
make_aware
(
value
,
self
.
default_timezone
)
elif
(
self
.
default_timezone
is
None
)
and
timezone
.
is_aware
(
value
):
if
(
field_timezone
is
not
None
)
and
not
timezone
.
is_aware
(
value
):
return
timezone
.
make_aware
(
value
,
field_timezone
)
elif
(
field_timezone
is
None
)
and
timezone
.
is_aware
(
value
):
return
timezone
.
make_naive
(
value
,
timezone
.
UTC
())
return
timezone
.
make_naive
(
value
,
timezone
.
UTC
())
return
value
return
value
def
default_timezone
(
self
):
return
timezone
.
get_default_timezone
()
if
settings
.
USE_TZ
else
None
def
to_internal_value
(
self
,
value
):
def
to_internal_value
(
self
,
value
):
input_formats
=
getattr
(
self
,
'input_formats'
,
api_settings
.
DATETIME_INPUT_FORMATS
)
if
isinstance
(
value
,
datetime
.
date
)
and
not
isinstance
(
value
,
datetime
.
datetime
):
if
isinstance
(
value
,
datetime
.
date
)
and
not
isinstance
(
value
,
datetime
.
datetime
):
self
.
fail
(
'date'
)
self
.
fail
(
'date'
)
if
isinstance
(
value
,
datetime
.
datetime
):
if
isinstance
(
value
,
datetime
.
datetime
):
return
self
.
enforce_timezone
(
value
)
return
self
.
enforce_timezone
(
value
)
for
format
in
self
.
input_formats
:
for
input_format
in
input_formats
:
if
format
.
lower
()
==
ISO_8601
:
if
input_
format
.
lower
()
==
ISO_8601
:
try
:
try
:
parsed
=
parse_datetime
(
value
)
parsed
=
parse_datetime
(
value
)
except
(
ValueError
,
TypeError
):
except
(
ValueError
,
TypeError
):
...
@@ -1037,25 +1045,27 @@ class DateTimeField(Field):
...
@@ -1037,25 +1045,27 @@ class DateTimeField(Field):
return
self
.
enforce_timezone
(
parsed
)
return
self
.
enforce_timezone
(
parsed
)
else
:
else
:
try
:
try
:
parsed
=
self
.
datetime_parser
(
value
,
format
)
parsed
=
self
.
datetime_parser
(
value
,
input_
format
)
except
(
ValueError
,
TypeError
):
except
(
ValueError
,
TypeError
):
pass
pass
else
:
else
:
return
self
.
enforce_timezone
(
parsed
)
return
self
.
enforce_timezone
(
parsed
)
humanized_format
=
humanize_datetime
.
datetime_formats
(
self
.
input_formats
)
humanized_format
=
humanize_datetime
.
datetime_formats
(
input_formats
)
self
.
fail
(
'invalid'
,
format
=
humanized_format
)
self
.
fail
(
'invalid'
,
format
=
humanized_format
)
def
to_representation
(
self
,
value
):
def
to_representation
(
self
,
value
):
if
self
.
format
is
None
:
output_format
=
getattr
(
self
,
'format'
,
api_settings
.
DATETIME_FORMAT
)
if
output_format
is
None
:
return
value
return
value
if
self
.
format
.
lower
()
==
ISO_8601
:
if
output_
format
.
lower
()
==
ISO_8601
:
value
=
value
.
isoformat
()
value
=
value
.
isoformat
()
if
value
.
endswith
(
'+00:00'
):
if
value
.
endswith
(
'+00:00'
):
value
=
value
[:
-
6
]
+
'Z'
value
=
value
[:
-
6
]
+
'Z'
return
value
return
value
return
value
.
strftime
(
self
.
format
)
return
value
.
strftime
(
output_
format
)
class
DateField
(
Field
):
class
DateField
(
Field
):
...
@@ -1063,24 +1073,26 @@ class DateField(Field):
...
@@ -1063,24 +1073,26 @@ class DateField(Field):
'invalid'
:
_
(
'Date has wrong format. Use one of these formats instead: {format}.'
),
'invalid'
:
_
(
'Date has wrong format. Use one of these formats instead: {format}.'
),
'datetime'
:
_
(
'Expected a date but got a datetime.'
),
'datetime'
:
_
(
'Expected a date but got a datetime.'
),
}
}
format
=
api_settings
.
DATE_FORMAT
input_formats
=
api_settings
.
DATE_INPUT_FORMATS
datetime_parser
=
datetime
.
datetime
.
strptime
datetime_parser
=
datetime
.
datetime
.
strptime
def
__init__
(
self
,
format
=
empty
,
input_formats
=
None
,
*
args
,
**
kwargs
):
def
__init__
(
self
,
format
=
empty
,
input_formats
=
None
,
*
args
,
**
kwargs
):
self
.
format
=
format
if
format
is
not
empty
else
self
.
format
if
format
is
not
empty
:
self
.
input_formats
=
input_formats
if
input_formats
is
not
None
else
self
.
input_formats
self
.
format
=
format
if
input_formats
is
not
None
:
self
.
input_formats
=
input_formats
super
(
DateField
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
super
(
DateField
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
def
to_internal_value
(
self
,
value
):
def
to_internal_value
(
self
,
value
):
input_formats
=
getattr
(
self
,
'input_formats'
,
api_settings
.
DATE_INPUT_FORMATS
)
if
isinstance
(
value
,
datetime
.
datetime
):
if
isinstance
(
value
,
datetime
.
datetime
):
self
.
fail
(
'datetime'
)
self
.
fail
(
'datetime'
)
if
isinstance
(
value
,
datetime
.
date
):
if
isinstance
(
value
,
datetime
.
date
):
return
value
return
value
for
format
in
self
.
input_formats
:
for
input_format
in
input_formats
:
if
format
.
lower
()
==
ISO_8601
:
if
input_
format
.
lower
()
==
ISO_8601
:
try
:
try
:
parsed
=
parse_date
(
value
)
parsed
=
parse_date
(
value
)
except
(
ValueError
,
TypeError
):
except
(
ValueError
,
TypeError
):
...
@@ -1090,20 +1102,22 @@ class DateField(Field):
...
@@ -1090,20 +1102,22 @@ class DateField(Field):
return
parsed
return
parsed
else
:
else
:
try
:
try
:
parsed
=
self
.
datetime_parser
(
value
,
format
)
parsed
=
self
.
datetime_parser
(
value
,
input_
format
)
except
(
ValueError
,
TypeError
):
except
(
ValueError
,
TypeError
):
pass
pass
else
:
else
:
return
parsed
.
date
()
return
parsed
.
date
()
humanized_format
=
humanize_datetime
.
date_formats
(
self
.
input_formats
)
humanized_format
=
humanize_datetime
.
date_formats
(
input_formats
)
self
.
fail
(
'invalid'
,
format
=
humanized_format
)
self
.
fail
(
'invalid'
,
format
=
humanized_format
)
def
to_representation
(
self
,
value
):
def
to_representation
(
self
,
value
):
output_format
=
getattr
(
self
,
'format'
,
api_settings
.
DATE_FORMAT
)
if
not
value
:
if
not
value
:
return
None
return
None
if
self
.
format
is
None
:
if
output_
format
is
None
:
return
value
return
value
# Applying a `DateField` to a datetime value is almost always
# Applying a `DateField` to a datetime value is almost always
...
@@ -1115,33 +1129,35 @@ class DateField(Field):
...
@@ -1115,33 +1129,35 @@ class DateField(Field):
'read-only field and deal with timezone issues explicitly.'
'read-only field and deal with timezone issues explicitly.'
)
)
if
self
.
format
.
lower
()
==
ISO_8601
:
if
output_
format
.
lower
()
==
ISO_8601
:
if
(
isinstance
(
value
,
str
)):
if
(
isinstance
(
value
,
str
)):
value
=
datetime
.
datetime
.
strptime
(
value
,
'
%
Y-
%
m-
%
d'
)
.
date
()
value
=
datetime
.
datetime
.
strptime
(
value
,
'
%
Y-
%
m-
%
d'
)
.
date
()
return
value
.
isoformat
()
return
value
.
isoformat
()
return
value
.
strftime
(
self
.
format
)
return
value
.
strftime
(
output_
format
)
class
TimeField
(
Field
):
class
TimeField
(
Field
):
default_error_messages
=
{
default_error_messages
=
{
'invalid'
:
_
(
'Time has wrong format. Use one of these formats instead: {format}.'
),
'invalid'
:
_
(
'Time has wrong format. Use one of these formats instead: {format}.'
),
}
}
format
=
api_settings
.
TIME_FORMAT
input_formats
=
api_settings
.
TIME_INPUT_FORMATS
datetime_parser
=
datetime
.
datetime
.
strptime
datetime_parser
=
datetime
.
datetime
.
strptime
def
__init__
(
self
,
format
=
empty
,
input_formats
=
None
,
*
args
,
**
kwargs
):
def
__init__
(
self
,
format
=
empty
,
input_formats
=
None
,
*
args
,
**
kwargs
):
self
.
format
=
format
if
format
is
not
empty
else
self
.
format
if
format
is
not
empty
:
self
.
input_formats
=
input_formats
if
input_formats
is
not
None
else
self
.
input_formats
self
.
format
=
format
if
input_formats
is
not
None
:
self
.
input_formats
=
input_formats
super
(
TimeField
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
super
(
TimeField
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
def
to_internal_value
(
self
,
value
):
def
to_internal_value
(
self
,
value
):
input_formats
=
getattr
(
self
,
'input_formats'
,
api_settings
.
TIME_INPUT_FORMATS
)
if
isinstance
(
value
,
datetime
.
time
):
if
isinstance
(
value
,
datetime
.
time
):
return
value
return
value
for
format
in
self
.
input_formats
:
for
input_format
in
input_formats
:
if
format
.
lower
()
==
ISO_8601
:
if
input_
format
.
lower
()
==
ISO_8601
:
try
:
try
:
parsed
=
parse_time
(
value
)
parsed
=
parse_time
(
value
)
except
(
ValueError
,
TypeError
):
except
(
ValueError
,
TypeError
):
...
@@ -1151,17 +1167,19 @@ class TimeField(Field):
...
@@ -1151,17 +1167,19 @@ class TimeField(Field):
return
parsed
return
parsed
else
:
else
:
try
:
try
:
parsed
=
self
.
datetime_parser
(
value
,
format
)
parsed
=
self
.
datetime_parser
(
value
,
input_
format
)
except
(
ValueError
,
TypeError
):
except
(
ValueError
,
TypeError
):
pass
pass
else
:
else
:
return
parsed
.
time
()
return
parsed
.
time
()
humanized_format
=
humanize_datetime
.
time_formats
(
self
.
input_formats
)
humanized_format
=
humanize_datetime
.
time_formats
(
input_formats
)
self
.
fail
(
'invalid'
,
format
=
humanized_format
)
self
.
fail
(
'invalid'
,
format
=
humanized_format
)
def
to_representation
(
self
,
value
):
def
to_representation
(
self
,
value
):
if
self
.
format
is
None
:
output_format
=
getattr
(
self
,
'format'
,
api_settings
.
TIME_FORMAT
)
if
output_format
is
None
:
return
value
return
value
# Applying a `TimeField` to a datetime value is almost always
# Applying a `TimeField` to a datetime value is almost always
...
@@ -1173,9 +1191,9 @@ class TimeField(Field):
...
@@ -1173,9 +1191,9 @@ class TimeField(Field):
'read-only field and deal with timezone issues explicitly.'
'read-only field and deal with timezone issues explicitly.'
)
)
if
self
.
format
.
lower
()
==
ISO_8601
:
if
output_
format
.
lower
()
==
ISO_8601
:
return
value
.
isoformat
()
return
value
.
isoformat
()
return
value
.
strftime
(
self
.
format
)
return
value
.
strftime
(
output_
format
)
class
DurationField
(
Field
):
class
DurationField
(
Field
):
...
@@ -1318,12 +1336,12 @@ class FileField(Field):
...
@@ -1318,12 +1336,12 @@ class FileField(Field):
'empty'
:
_
(
'The submitted file is empty.'
),
'empty'
:
_
(
'The submitted file is empty.'
),
'max_length'
:
_
(
'Ensure this filename has at most {max_length} characters (it has {length}).'
),
'max_length'
:
_
(
'Ensure this filename has at most {max_length} characters (it has {length}).'
),
}
}
use_url
=
api_settings
.
UPLOADED_FILES_USE_URL
def
__init__
(
self
,
*
args
,
**
kwargs
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
self
.
max_length
=
kwargs
.
pop
(
'max_length'
,
None
)
self
.
max_length
=
kwargs
.
pop
(
'max_length'
,
None
)
self
.
allow_empty_file
=
kwargs
.
pop
(
'allow_empty_file'
,
False
)
self
.
allow_empty_file
=
kwargs
.
pop
(
'allow_empty_file'
,
False
)
self
.
use_url
=
kwargs
.
pop
(
'use_url'
,
self
.
use_url
)
if
'use_url'
in
kwargs
:
self
.
use_url
=
kwargs
.
pop
(
'use_url'
)
super
(
FileField
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
super
(
FileField
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
def
to_internal_value
(
self
,
data
):
def
to_internal_value
(
self
,
data
):
...
@@ -1344,10 +1362,12 @@ class FileField(Field):
...
@@ -1344,10 +1362,12 @@ class FileField(Field):
return
data
return
data
def
to_representation
(
self
,
value
):
def
to_representation
(
self
,
value
):
use_url
=
getattr
(
self
,
'use_url'
,
api_settings
.
UPLOADED_FILES_USE_URL
)
if
not
value
:
if
not
value
:
return
None
return
None
if
self
.
use_url
:
if
use_url
:
if
not
getattr
(
value
,
'url'
,
None
):
if
not
getattr
(
value
,
'url'
,
None
):
# If the file has not been saved it may not have a URL.
# If the file has not been saved it may not have a URL.
return
None
return
None
...
...
rest_framework/serializers.py
View file @
6284bcea
...
@@ -797,7 +797,7 @@ class ModelSerializer(Serializer):
...
@@ -797,7 +797,7 @@ class ModelSerializer(Serializer):
# you'll also need to ensure you update the `create` method on any generic
# you'll also need to ensure you update the `create` method on any generic
# views, to correctly handle the 'Location' response header for
# views, to correctly handle the 'Location' response header for
# "HTTP 201 Created" responses.
# "HTTP 201 Created" responses.
url_field_name
=
api_settings
.
URL_FIELD_NAME
url_field_name
=
None
# Default `create` and `update` behavior...
# Default `create` and `update` behavior...
def
create
(
self
,
validated_data
):
def
create
(
self
,
validated_data
):
...
@@ -880,6 +880,9 @@ class ModelSerializer(Serializer):
...
@@ -880,6 +880,9 @@ class ModelSerializer(Serializer):
Return the dict of field names -> field instances that should be
Return the dict of field names -> field instances that should be
used for `self.fields` when instantiating the serializer.
used for `self.fields` when instantiating the serializer.
"""
"""
if
self
.
url_field_name
is
None
:
self
.
url_field_name
=
api_settings
.
URL_FIELD_NAME
assert
hasattr
(
self
,
'Meta'
),
(
assert
hasattr
(
self
,
'Meta'
),
(
'Class {serializer_class} missing "Meta" attribute'
.
format
(
'Class {serializer_class} missing "Meta" attribute'
.
format
(
serializer_class
=
self
.
__class__
.
__name__
serializer_class
=
self
.
__class__
.
__name__
...
...
rest_framework/settings.py
View file @
6284bcea
...
@@ -26,8 +26,6 @@ from django.utils import six
...
@@ -26,8 +26,6 @@ from django.utils import six
from
rest_framework
import
ISO_8601
from
rest_framework
import
ISO_8601
from
rest_framework.compat
import
importlib
from
rest_framework.compat
import
importlib
USER_SETTINGS
=
getattr
(
settings
,
'REST_FRAMEWORK'
,
None
)
DEFAULTS
=
{
DEFAULTS
=
{
# Base API policies
# Base API policies
'DEFAULT_RENDERER_CLASSES'
:
(
'DEFAULT_RENDERER_CLASSES'
:
(
...
@@ -188,10 +186,17 @@ class APISettings(object):
...
@@ -188,10 +186,17 @@ class APISettings(object):
and return the class, rather than the string literal.
and return the class, rather than the string literal.
"""
"""
def
__init__
(
self
,
user_settings
=
None
,
defaults
=
None
,
import_strings
=
None
):
def
__init__
(
self
,
user_settings
=
None
,
defaults
=
None
,
import_strings
=
None
):
self
.
user_settings
=
user_settings
or
{}
if
user_settings
:
self
.
_user_settings
=
user_settings
self
.
defaults
=
defaults
or
DEFAULTS
self
.
defaults
=
defaults
or
DEFAULTS
self
.
import_strings
=
import_strings
or
IMPORT_STRINGS
self
.
import_strings
=
import_strings
or
IMPORT_STRINGS
@property
def
user_settings
(
self
):
if
not
hasattr
(
self
,
'_user_settings'
):
self
.
_user_settings
=
getattr
(
settings
,
'REST_FRAMEWORK'
,
{})
return
self
.
_user_settings
def
__getattr__
(
self
,
attr
):
def
__getattr__
(
self
,
attr
):
if
attr
not
in
self
.
defaults
.
keys
():
if
attr
not
in
self
.
defaults
.
keys
():
raise
AttributeError
(
"Invalid API setting: '
%
s'"
%
attr
)
raise
AttributeError
(
"Invalid API setting: '
%
s'"
%
attr
)
...
@@ -212,7 +217,7 @@ class APISettings(object):
...
@@ -212,7 +217,7 @@ class APISettings(object):
return
val
return
val
api_settings
=
APISettings
(
USER_SETTINGS
,
DEFAULTS
,
IMPORT_STRINGS
)
api_settings
=
APISettings
(
None
,
DEFAULTS
,
IMPORT_STRINGS
)
def
reload_api_settings
(
*
args
,
**
kwargs
):
def
reload_api_settings
(
*
args
,
**
kwargs
):
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment