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
3a06dde8
Commit
3a06dde8
authored
Oct 04, 2012
by
Tom Christie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Clean up field classes
parent
d89d6887
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
168 additions
and
146 deletions
+168
-146
rest_framework/fields.py
+151
-131
rest_framework/serializers.py
+17
-15
No files found.
rest_framework/fields.py
View file @
3a06dde8
...
...
@@ -26,21 +26,88 @@ def is_simple_callable(obj):
class
Field
(
object
):
creation_counter
=
0
default_validators
=
[]
default_error_messages
=
{
'required'
:
_
(
'This field is required.'
),
'invalid'
:
_
(
'Invalid value.'
),
}
empty
=
''
def
__init__
(
self
,
source
=
None
,
readonly
=
False
,
required
=
None
,
validators
=
[],
error_messages
=
None
):
def
__init__
(
self
,
source
=
None
):
self
.
parent
=
None
self
.
creation_counter
=
Field
.
creation_counter
Field
.
creation_counter
+=
1
self
.
source
=
source
def
initialize
(
self
,
parent
):
"""
Called to set up a field prior to field_to_native or field_from_native.
parent - The parent serializer.
model_field - The model field this field corrosponds to, if one exists.
"""
self
.
parent
=
parent
self
.
root
=
parent
.
root
or
parent
self
.
context
=
self
.
root
.
context
def
field_from_native
(
self
,
data
,
field_name
,
into
):
"""
Given a dictionary and a field name, updates the dictionary `into`,
with the field and it's deserialized value.
"""
return
def
field_to_native
(
self
,
obj
,
field_name
):
"""
Given and object and a field name, returns the value that should be
serialized for that field.
"""
if
obj
is
None
:
return
self
.
empty
if
self
.
source
==
'*'
:
return
self
.
to_native
(
obj
)
if
self
.
source
:
value
=
obj
for
component
in
self
.
source
.
split
(
'.'
):
value
=
getattr
(
value
,
component
)
else
:
value
=
getattr
(
obj
,
field_name
)
return
self
.
to_native
(
value
)
def
to_native
(
self
,
value
):
"""
Converts the field's value into it's simple representation.
"""
if
is_simple_callable
(
value
):
value
=
value
()
if
is_protected_type
(
value
):
return
value
elif
hasattr
(
value
,
'__iter__'
)
and
not
isinstance
(
value
,
(
dict
,
basestring
)):
return
[
self
.
to_native
(
item
)
for
item
in
value
]
return
smart_unicode
(
value
)
def
attributes
(
self
):
"""
Returns a dictionary of attributes to be used when serializing to xml.
"""
if
getattr
(
self
,
'type_name'
,
None
):
return
{
'type'
:
self
.
type_name
}
return
{}
class
WritableField
(
Field
):
"""
Base for read/write fields.
"""
default_validators
=
[]
default_error_messages
=
{
'required'
:
_
(
'This field is required.'
),
'invalid'
:
_
(
'Invalid value.'
),
}
def
__init__
(
self
,
source
=
None
,
readonly
=
False
,
required
=
None
,
validators
=
[],
error_messages
=
None
):
super
(
WritableField
,
self
)
.
__init__
(
source
=
source
)
self
.
readonly
=
readonly
if
required
is
None
:
self
.
required
=
not
(
readonly
)
...
...
@@ -56,19 +123,6 @@ class Field(object):
self
.
validators
=
self
.
default_validators
+
validators
def
initialize
(
self
,
parent
,
model_field
=
None
):
"""
Called to set up a field prior to field_to_native or field_from_native.
parent - The parent serializer.
model_field - The model field this field corrosponds to, if one exists.
"""
self
.
parent
=
parent
self
.
root
=
parent
.
root
or
parent
self
.
context
=
self
.
root
.
context
if
model_field
:
self
.
model_field
=
model_field
def
validate
(
self
,
value
):
if
value
in
validators
.
EMPTY_VALUES
and
self
.
required
:
raise
ValidationError
(
self
.
error_messages
[
'required'
])
...
...
@@ -117,96 +171,75 @@ class Field(object):
"""
Reverts a simple representation back to the field's value.
"""
if
hasattr
(
self
,
'model_field'
):
try
:
return
self
.
model_field
.
rel
.
to
.
_meta
.
get_field
(
self
.
model_field
.
rel
.
field_name
)
.
to_python
(
value
)
except
:
return
self
.
model_field
.
to_python
(
value
)
return
value
def
field_to_native
(
self
,
obj
,
field_name
):
"""
Given and object and a field name, returns the value that should be
serialized for that field.
"""
if
obj
is
None
:
return
self
.
empty
if
self
.
source
==
'*'
:
return
self
.
to_native
(
obj
)
self
.
obj
=
obj
# Need to hang onto this in the case of model fields
if
hasattr
(
self
,
'model_field'
):
return
self
.
to_native
(
self
.
model_field
.
_get_val_from_obj
(
obj
))
if
self
.
source
:
value
=
obj
for
component
in
self
.
source
.
split
(
'.'
):
value
=
getattr
(
value
,
component
)
else
:
value
=
getattr
(
obj
,
field_name
)
return
self
.
to_native
(
value
)
def
to_native
(
self
,
value
):
class
ModelField
(
WritableField
):
"""
Converts the field's value into it's simple representation
.
A generic field that can be used against an arbirtrary model field
.
"""
if
is_simple_callable
(
value
):
value
=
value
()
def
__init__
(
self
,
*
args
,
**
kwargs
):
try
:
self
.
model_field
=
kwargs
.
pop
(
'model_field'
)
except
:
raise
ValueError
(
"ModelField requires 'model_field' kwarg"
)
super
(
ModelField
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
def
from_native
(
self
,
value
):
try
:
rel
=
self
.
model_field
.
rel
except
:
return
self
.
model_field
.
to_python
(
value
)
return
rel
.
to
.
_meta
.
get_field
(
rel
.
field_name
)
.
to_python
(
value
)
def
field_to_native
(
self
,
obj
,
field_name
):
value
=
self
.
model_field
.
_get_val_from_obj
(
obj
)
if
is_protected_type
(
value
):
return
value
elif
hasattr
(
self
,
'model_field'
):
return
self
.
model_field
.
value_to_string
(
self
.
obj
)
elif
hasattr
(
value
,
'__iter__'
)
and
not
isinstance
(
value
,
(
dict
,
basestring
)):
return
[
self
.
to_native
(
item
)
for
item
in
value
]
return
smart_unicode
(
value
)
def
attributes
(
self
):
"""
Returns a dictionary of attributes to be used when serializing to xml.
"""
try
:
return
{
"type"
:
self
.
model_field
.
get_internal_type
()
}
except
AttributeError
:
return
{}
class
HyperlinkedIdentityField
(
Field
):
def
field_to_native
(
self
,
obj
,
field_name
):
request
=
self
.
context
.
get
(
'request'
,
None
)
view_name
=
self
.
parent
.
opts
.
view_name
view_kwargs
=
{
'pk'
:
obj
.
pk
}
return
reverse
(
view_name
,
kwargs
=
view_kwargs
,
request
=
request
)
##### Relational fields #####
class
RelatedField
(
Field
):
class
RelatedField
(
Writable
Field
):
"""
A base class for model related fields or related managers.
Subclass this and override `convert` to define custom behaviour when
serializing related objects.
Base class for related model fields.
"""
def
__init__
(
self
,
*
args
,
**
kwargs
):
self
.
queryset
=
kwargs
.
pop
(
'queryset'
,
None
)
super
(
RelatedField
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
def
field_to_native
(
self
,
obj
,
field_name
):
obj
=
getattr
(
obj
,
self
.
source
or
field_name
)
if
obj
.
__class__
.
__name__
in
(
'RelatedManager'
,
'ManyRelatedManager'
):
return
[
self
.
to_native
(
item
)
for
item
in
obj
.
all
()]
return
self
.
to_native
(
obj
)
value
=
getattr
(
obj
,
self
.
source
or
field_name
)
return
self
.
to_native
(
value
)
def
attributes
(
self
):
def
field_from_native
(
self
,
data
,
field_name
,
into
):
value
=
data
.
get
(
field_name
)
into
[(
self
.
source
or
field_name
)
+
'_id'
]
=
self
.
from_native
(
value
)
class
ManyRelatedField
(
RelatedField
):
"""
Base class for related model managers.
"""
def
field_to_native
(
self
,
obj
,
field_name
):
value
=
getattr
(
obj
,
self
.
source
or
field_name
)
return
[
self
.
to_native
(
item
)
for
item
in
value
.
all
()]
def
field_from_native
(
self
,
data
,
field_name
,
into
):
try
:
return
{
"rel"
:
self
.
model_field
.
rel
.
__class__
.
__name__
,
"to"
:
smart_unicode
(
self
.
model_field
.
rel
.
to
.
_meta
)
}
except
AttributeError
:
return
{}
value
=
data
.
getlist
(
self
.
source
or
field_name
)
except
:
value
=
data
.
get
(
self
.
source
or
field_name
)
else
:
if
value
==
[
''
]:
value
=
[]
into
[
field_name
]
=
[
self
.
from_native
(
item
)
for
item
in
value
]
class
PrimaryKeyRelatedField
(
RelatedField
):
...
...
@@ -215,20 +248,11 @@ class PrimaryKeyRelatedField(RelatedField):
"""
def
to_native
(
self
,
pk
):
"""
You can subclass this method to provide different serialization
behavior based on the pk.
"""
return
pk
def
field_to_native
(
self
,
obj
,
field_name
):
# This is only implemented for performance reasons
#
# We could leave the default `RelatedField.field_to_native()` in place,
# and inside just implement `to_native()` as `return obj.pk`
#
# That would involve an extra database lookup.
try
:
# Prefer obj.serializable_value for performance reasons
pk
=
obj
.
serializable_value
(
self
.
source
or
field_name
)
except
AttributeError
:
# RelatedObject (reverse relationship)
...
...
@@ -237,18 +261,17 @@ class PrimaryKeyRelatedField(RelatedField):
# Forward relationship
return
self
.
to_native
(
pk
)
def
field_from_native
(
self
,
data
,
field_name
,
into
):
value
=
data
.
get
(
field_name
)
into
[
field_name
+
'_id'
]
=
self
.
from_native
(
value
)
class
ManyPrimaryKeyRelatedField
(
PrimaryKe
yRelatedField
):
class
ManyPrimaryKeyRelatedField
(
Man
yRelatedField
):
"""
Serializes a to-many related field or related manager to a pk value.
"""
def
to_native
(
self
,
pk
):
return
pk
def
field_to_native
(
self
,
obj
,
field_name
):
try
:
# Prefer obj.serializable_value for performance reasons
queryset
=
obj
.
serializable_value
(
self
.
source
or
field_name
)
except
AttributeError
:
# RelatedManager (reverse relationship)
...
...
@@ -257,40 +280,25 @@ class ManyPrimaryKeyRelatedField(PrimaryKeyRelatedField):
# Forward relationship
return
[
self
.
to_native
(
item
.
pk
)
for
item
in
queryset
.
all
()]
def
field_from_native
(
self
,
data
,
field_name
,
into
):
try
:
value
=
data
.
getlist
(
field_name
)
except
:
value
=
data
.
get
(
field_name
)
else
:
if
value
==
[
''
]:
value
=
[]
into
[
field_name
]
=
[
self
.
from_native
(
item
)
for
item
in
value
]
class
NaturalKeyRelatedField
(
Related
Field
):
class
HyperlinkedIdentityField
(
Field
):
"""
Serializes a model related field or related manager to a natural key value
.
A field that represents the model's identity using a hyperlink
.
"""
is_natural_key
=
True
# XML renderer handles these differently
def
to_native
(
self
,
obj
):
if
hasattr
(
obj
,
'natural_key'
):
return
obj
.
natural_key
()
return
obj
def
__init__
(
self
,
*
args
,
**
kwargs
):
pass
def
field_from_native
(
self
,
data
,
field_name
,
into
):
value
=
data
.
get
(
field_name
)
into
[
self
.
model_field
.
attname
]
=
self
.
from_native
(
value
)
def
field_to_native
(
self
,
obj
,
field_name
):
request
=
self
.
context
.
get
(
'request'
,
None
)
view_name
=
self
.
parent
.
opts
.
view_name
view_kwargs
=
{
'pk'
:
obj
.
pk
}
return
reverse
(
view_name
,
kwargs
=
view_kwargs
,
request
=
request
)
def
from_native
(
self
,
value
):
# TODO: Support 'using' : db = options.pop('using', DEFAULT_DB_ALIAS)
manager
=
self
.
model_field
.
rel
.
to
.
_default_manager
manager
=
manager
.
db_manager
(
DEFAULT_DB_ALIAS
)
return
manager
.
get_by_natural_key
(
*
value
)
.
pk
##### Typed Fields #####
class
BooleanField
(
Field
):
class
BooleanField
(
WritableField
):
type_name
=
'BooleanField'
default_error_messages
=
{
'invalid'
:
_
(
u"'
%
s' value must be either True or False."
),
}
...
...
@@ -307,7 +315,9 @@ class BooleanField(Field):
raise
ValidationError
(
self
.
error_messages
[
'invalid'
]
%
value
)
class
CharField
(
Field
):
class
CharField
(
WritableField
):
type_name
=
'CharField'
def
__init__
(
self
,
max_length
=
None
,
min_length
=
None
,
*
args
,
**
kwargs
):
self
.
max_length
,
self
.
min_length
=
max_length
,
min_length
super
(
CharField
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
...
...
@@ -323,6 +333,8 @@ class CharField(Field):
class
EmailField
(
CharField
):
type_name
=
'EmailField'
default_error_messages
=
{
'invalid'
:
_
(
'Enter a valid e-mail address.'
),
}
...
...
@@ -339,7 +351,9 @@ class EmailField(CharField):
return
result
class
DateField
(
Field
):
class
DateField
(
WritableField
):
type_name
=
'DateField'
default_error_messages
=
{
'invalid'
:
_
(
u"'
%
s' value has an invalid date format. It must be "
u"in YYYY-MM-DD format."
),
...
...
@@ -373,7 +387,9 @@ class DateField(Field):
raise
ValidationError
(
msg
)
class
DateTimeField
(
Field
):
class
DateTimeField
(
WritableField
):
type_name
=
'DateTimeField'
default_error_messages
=
{
'invalid'
:
_
(
u"'
%
s' value has an invalid format. It must be in "
u"YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format."
),
...
...
@@ -424,7 +440,9 @@ class DateTimeField(Field):
raise
ValidationError
(
msg
)
class
IntegerField
(
Field
):
class
IntegerField
(
WritableField
):
type_name
=
'IntegerField'
default_error_messages
=
{
'invalid'
:
_
(
'Enter a whole number.'
),
'max_value'
:
_
(
'Ensure this value is less than or equal to
%(limit_value)
s.'
),
...
...
@@ -450,7 +468,9 @@ class IntegerField(Field):
return
value
class
FloatField
(
Field
):
class
FloatField
(
WritableField
):
type_name
=
'FloatField'
default_error_messages
=
{
'invalid'
:
_
(
"'
%
s' value must be a float."
),
}
...
...
rest_framework/serializers.py
View file @
3a06dde8
...
...
@@ -123,16 +123,8 @@ class BaseSerializer(Field):
# Get the explicitly declared fields
for
key
,
field
in
self
.
fields
.
items
():
ret
[
key
]
=
field
# Determine if the declared field corrosponds to a model field.
try
:
if
key
==
'pk'
:
model_field
=
obj
.
_meta
.
pk
else
:
model_field
=
obj
.
_meta
.
get_field_by_name
(
key
)[
0
]
except
:
model_field
=
None
# Set up the field
field
.
initialize
(
parent
=
self
,
model_field
=
model_field
)
field
.
initialize
(
parent
=
self
)
# Add in the default fields
fields
=
self
.
default_fields
(
serialize
,
obj
,
data
,
nested
)
...
...
@@ -157,12 +149,12 @@ class BaseSerializer(Field):
#####
# Field methods - used when the serializer class is itself used as a field.
def
initialize
(
self
,
parent
,
model_field
=
None
):
def
initialize
(
self
,
parent
):
"""
Same behaviour as usual Field, except that we need to keep track
of state so that we can deal with handling maximum depth and recursion.
"""
super
(
BaseSerializer
,
self
)
.
initialize
(
parent
,
model_field
)
super
(
BaseSerializer
,
self
)
.
initialize
(
parent
)
self
.
stack
=
parent
.
stack
[:]
if
parent
.
opts
.
nested
and
not
isinstance
(
parent
.
opts
.
nested
,
bool
):
self
.
opts
.
nested
=
parent
.
opts
.
nested
-
1
...
...
@@ -296,12 +288,22 @@ class ModelSerializerOptions(SerializerOptions):
self
.
model
=
getattr
(
meta
,
'model'
,
None
)
class
ModelSerializer
(
RelatedField
,
Serializer
):
class
ModelSerializer
(
Serializer
):
"""
A serializer that deals with model instances and querysets.
"""
_options_class
=
ModelSerializerOptions
def
field_to_native
(
self
,
obj
,
field_name
):
"""
Override default so that we can apply ModelSerializer as a nested
field to relationships.
"""
obj
=
getattr
(
obj
,
self
.
source
or
field_name
)
if
obj
.
__class__
.
__name__
in
(
'RelatedManager'
,
'ManyRelatedManager'
):
return
[
self
.
to_native
(
item
)
for
item
in
obj
.
all
()]
return
self
.
to_native
(
obj
)
def
default_fields
(
self
,
serialize
,
obj
=
None
,
data
=
None
,
nested
=
False
):
"""
Return all the fields that should be serialized for the model.
...
...
@@ -330,7 +332,7 @@ class ModelSerializer(RelatedField, Serializer):
field
=
self
.
get_field
(
model_field
)
if
field
:
field
.
initialize
(
parent
=
self
,
model_field
=
model_field
)
field
.
initialize
(
parent
=
self
)
ret
[
model_field
.
name
]
=
field
return
ret
...
...
@@ -339,7 +341,7 @@ class ModelSerializer(RelatedField, Serializer):
"""
Returns a default instance of the pk field.
"""
return
Field
(
readonly
=
True
)
return
Field
()
def
get_nested_field
(
self
,
model_field
):
"""
...
...
@@ -373,7 +375,7 @@ class ModelSerializer(RelatedField, Serializer):
try
:
return
field_mapping
[
model_field
.
__class__
]()
except
KeyError
:
return
Field
(
)
return
ModelField
(
model_field
=
model_field
)
def
restore_object
(
self
,
attrs
,
instance
=
None
):
"""
...
...
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