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
75e81b82
Commit
75e81b82
authored
Dec 19, 2014
by
Tom Christie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
build_*_field methods
parent
f72928ea
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
313 additions
and
250 deletions
+313
-250
rest_framework/serializers.py
+313
-250
No files found.
rest_framework/serializers.py
View file @
75e81b82
...
@@ -696,7 +696,7 @@ class ModelSerializer(Serializer):
...
@@ -696,7 +696,7 @@ class ModelSerializer(Serializer):
you need you should either declare the extra/differing fields explicitly on
you need you should either declare the extra/differing fields explicitly on
the serializer class, or simply use a `Serializer` class.
the serializer class, or simply use a `Serializer` class.
"""
"""
_field_mapping
=
ClassLookupDict
(
{
serializer_field_mapping
=
{
models
.
AutoField
:
IntegerField
,
models
.
AutoField
:
IntegerField
,
models
.
BigIntegerField
:
IntegerField
,
models
.
BigIntegerField
:
IntegerField
,
models
.
BooleanField
:
BooleanField
,
models
.
BooleanField
:
BooleanField
,
...
@@ -719,8 +719,8 @@ class ModelSerializer(Serializer):
...
@@ -719,8 +719,8 @@ class ModelSerializer(Serializer):
models
.
TextField
:
CharField
,
models
.
TextField
:
CharField
,
models
.
TimeField
:
TimeField
,
models
.
TimeField
:
TimeField
,
models
.
URLField
:
URLField
,
models
.
URLField
:
URLField
,
}
)
}
_related_class
=
PrimaryKeyRelatedField
serializer
_related_class
=
PrimaryKeyRelatedField
# Default `create` and `update` behavior...
# Default `create` and `update` behavior...
...
@@ -793,98 +793,13 @@ class ModelSerializer(Serializer):
...
@@ -793,98 +793,13 @@ class ModelSerializer(Serializer):
return
instance
return
instance
# Determine the validators to apply...
def
get_validators
(
self
):
"""
Determine the set of validators to use when instantiating serializer.
"""
# If the validators have been declared explicitly then use that.
validators
=
getattr
(
getattr
(
self
,
'Meta'
,
None
),
'validators'
,
None
)
if
validators
is
not
None
:
return
validators
# Otherwise use the default set of validators.
return
(
self
.
get_unique_together_validators
()
+
self
.
get_unique_for_date_validators
()
)
def
get_unique_together_validators
(
self
):
"""
Determine a default set of validators for any unique_together contraints.
"""
model_class_inheritance_tree
=
(
[
self
.
Meta
.
model
]
+
list
(
self
.
Meta
.
model
.
_meta
.
parents
.
keys
())
)
# The field names we're passing though here only include fields
# which may map onto a model field. Any dotted field name lookups
# cannot map to a field, and must be a traversal, so we're not
# including those.
field_names
=
set
([
field
.
source
for
field
in
self
.
fields
.
values
()
if
(
field
.
source
!=
'*'
)
and
(
'.'
not
in
field
.
source
)
])
# Note that we make sure to check `unique_together` both on the
# base model class, but also on any parent classes.
validators
=
[]
for
parent_class
in
model_class_inheritance_tree
:
for
unique_together
in
parent_class
.
_meta
.
unique_together
:
if
field_names
.
issuperset
(
set
(
unique_together
)):
validator
=
UniqueTogetherValidator
(
queryset
=
parent_class
.
_default_manager
,
fields
=
unique_together
)
validators
.
append
(
validator
)
return
validators
def
get_unique_for_date_validators
(
self
):
"""
Determine a default set of validators for the following contraints:
* unique_for_date
* unique_for_month
* unique_for_year
"""
info
=
model_meta
.
get_field_info
(
self
.
Meta
.
model
)
default_manager
=
self
.
Meta
.
model
.
_default_manager
field_names
=
[
field
.
source
for
field
in
self
.
fields
.
values
()]
validators
=
[]
for
field_name
,
field
in
info
.
fields_and_pk
.
items
():
if
field
.
unique_for_date
and
field_name
in
field_names
:
validator
=
UniqueForDateValidator
(
queryset
=
default_manager
,
field
=
field_name
,
date_field
=
field
.
unique_for_date
)
validators
.
append
(
validator
)
if
field
.
unique_for_month
and
field_name
in
field_names
:
validator
=
UniqueForMonthValidator
(
queryset
=
default_manager
,
field
=
field_name
,
date_field
=
field
.
unique_for_month
)
validators
.
append
(
validator
)
if
field
.
unique_for_year
and
field_name
in
field_names
:
validator
=
UniqueForYearValidator
(
queryset
=
default_manager
,
field
=
field_name
,
date_field
=
field
.
unique_for_year
)
validators
.
append
(
validator
)
return
validators
# Determine the fields to apply...
# Determine the fields to apply...
def
get_fields
(
self
):
def
get_fields
(
self
):
"""
Return the dict of field names -> field instances that should be
used for `self.fields` when instantiating the serializer.
"""
declared_fields
=
copy
.
deepcopy
(
self
.
_declared_fields
)
declared_fields
=
copy
.
deepcopy
(
self
.
_declared_fields
)
model
=
getattr
(
self
.
Meta
,
'model'
)
model
=
getattr
(
self
.
Meta
,
'model'
)
depth
=
getattr
(
self
.
Meta
,
'depth'
,
0
)
depth
=
getattr
(
self
.
Meta
,
'depth'
,
0
)
...
@@ -912,7 +827,7 @@ class ModelSerializer(Serializer):
...
@@ -912,7 +827,7 @@ class ModelSerializer(Serializer):
field_cls
,
kwargs
=
self
.
build_field
(
field_name
,
info
,
model
,
depth
)
field_cls
,
kwargs
=
self
.
build_field
(
field_name
,
info
,
model
,
depth
)
# Populate any kwargs defined in `Meta.extra_kwargs`
# Populate any kwargs defined in `Meta.extra_kwargs`
kwargs
=
self
.
build_fi
nal
_kwargs
(
kwargs
,
extra_kwargs
,
field_name
)
kwargs
=
self
.
build_fi
eld
_kwargs
(
kwargs
,
extra_kwargs
,
field_name
)
# Create the serializer field.
# Create the serializer field.
ret
[
field_name
]
=
field_cls
(
**
kwargs
)
ret
[
field_name
]
=
field_cls
(
**
kwargs
)
...
@@ -922,12 +837,114 @@ class ModelSerializer(Serializer):
...
@@ -922,12 +837,114 @@ class ModelSerializer(Serializer):
return
ret
return
ret
def
build_field
(
self
,
field_name
,
info
,
model
,
depth
):
# Methods for determining the set of field names to include...
def
get_field_names
(
self
,
declared_fields
,
info
):
"""
Returns the list of all field names that should be created when
instantiating this serializer class. This is based on the default
set of fields, but also takes into account the `Meta.fields` or
`Meta.exclude` options if they have been specified.
"""
fields
=
getattr
(
self
.
Meta
,
'fields'
,
None
)
exclude
=
getattr
(
self
.
Meta
,
'exclude'
,
None
)
if
fields
and
not
isinstance
(
fields
,
(
list
,
tuple
)):
raise
TypeError
(
'The `fields` option must be a list or tuple. Got
%
s.'
%
type
(
fields
)
.
__name__
)
if
exclude
and
not
isinstance
(
exclude
,
(
list
,
tuple
)):
raise
TypeError
(
'The `exclude` option must be a list or tuple. Got
%
s.'
%
type
(
exclude
)
.
__name__
)
assert
not
(
fields
and
exclude
),
(
"Cannot set both 'fields' and 'exclude' options on "
"serializer {serializer_class}."
.
format
(
serializer_class
=
self
.
__class__
.
__name__
)
)
if
fields
is
not
None
:
# Ensure that all declared fields have also been included in the
# `Meta.fields` option.
for
field_name
in
declared_fields
:
assert
field_name
in
fields
,
(
"The field '{field_name}' was declared on serializer "
"{serializer_class}, but has not been included in the "
"'fields' option."
.
format
(
field_name
=
field_name
,
serializer_class
=
self
.
__class__
.
__name__
)
)
return
fields
# Use the default set of field names if `Meta.fields` is not specified.
fields
=
self
.
get_default_field_names
(
declared_fields
,
info
)
if
exclude
is
not
None
:
# If `Meta.exclude` is included, then remove those fields.
for
field_name
in
exclude
:
assert
field_name
in
fields
,
(
"The field '{field_name}' was include on serializer "
"{serializer_class} in the 'exclude' option, but does "
"not match any model field."
.
format
(
field_name
=
field_name
,
serializer_class
=
self
.
__class__
.
__name__
)
)
fields
.
remove
(
field_name
)
return
fields
def
get_default_field_names
(
self
,
declared_fields
,
model_info
):
"""
Return the default list of field names that will be used if the
`Meta.fields` option is not specified.
"""
return
(
[
model_info
.
pk
.
name
]
+
list
(
declared_fields
.
keys
())
+
list
(
model_info
.
fields
.
keys
())
+
list
(
model_info
.
forward_relations
.
keys
())
)
# Methods for constructing serializer fields...
def
build_field
(
self
,
field_name
,
info
,
model
,
nested_depth
):
"""
Return a two tuple of (cls, kwargs) to build a serializer field with.
"""
if
field_name
in
info
.
fields_and_pk
:
if
field_name
in
info
.
fields_and_pk
:
# Create regular model fields.
return
self
.
build_standard_field
(
field_name
,
info
,
model
)
elif
field_name
in
info
.
relations
:
if
not
nested_depth
:
return
self
.
build_relational_field
(
field_name
,
info
,
model
)
else
:
return
self
.
build_nested_field
(
field_name
,
info
,
model
,
nested_depth
)
elif
hasattr
(
model
,
field_name
):
return
self
.
build_property_field
(
field_name
,
info
,
model
)
elif
field_name
==
api_settings
.
URL_FIELD_NAME
:
return
self
.
build_url_field
(
field_name
,
info
,
model
)
return
self
.
build_unknown_field
(
field_name
,
info
,
model
)
def
build_standard_field
(
self
,
field_name
,
info
,
model
):
"""
Create regular model fields.
"""
field_mapping
=
ClassLookupDict
(
self
.
serializer_field_mapping
)
model_field
=
info
.
fields_and_pk
[
field_name
]
model_field
=
info
.
fields_and_pk
[
field_name
]
field_cls
=
self
.
_field_mapping
[
model_field
]
field_cls
=
field_mapping
[
model_field
]
kwargs
=
get_field_kwargs
(
field_name
,
model_field
)
kwargs
=
get_field_kwargs
(
field_name
,
model_field
)
if
'choices'
in
kwargs
:
if
'choices'
in
kwargs
:
# Fields with choices get coerced into `ChoiceField`
# Fields with choices get coerced into `ChoiceField`
# instead of using their regular typed field.
# instead of using their regular typed field.
...
@@ -941,38 +958,67 @@ class ModelSerializer(Serializer):
...
@@ -941,38 +958,67 @@ class ModelSerializer(Serializer):
# `allow_blank` is only valid for textual fields.
# `allow_blank` is only valid for textual fields.
kwargs
.
pop
(
'allow_blank'
,
None
)
kwargs
.
pop
(
'allow_blank'
,
None
)
elif
field_name
in
info
.
relations
:
return
field_cls
,
kwargs
# Create forward and reverse relationships.
def
build_relational_field
(
self
,
field_name
,
info
,
model
):
"""
Create fields for forward and reverse relationships.
"""
relation_info
=
info
.
relations
[
field_name
]
relation_info
=
info
.
relations
[
field_name
]
if
depth
:
field_cls
=
self
.
_get_nested_class
(
depth
,
relation_info
)
field_cls
=
self
.
serializer_related_class
kwargs
=
get_nested_relation_kwargs
(
relation_info
)
else
:
field_cls
=
self
.
_related_class
kwargs
=
get_relation_kwargs
(
field_name
,
relation_info
)
kwargs
=
get_relation_kwargs
(
field_name
,
relation_info
)
# `view_name` is only valid for hyperlinked relationships.
# `view_name` is only valid for hyperlinked relationships.
if
not
issubclass
(
field_cls
,
HyperlinkedRelatedField
):
if
not
issubclass
(
field_cls
,
HyperlinkedRelatedField
):
kwargs
.
pop
(
'view_name'
,
None
)
kwargs
.
pop
(
'view_name'
,
None
)
elif
hasattr
(
model
,
field_name
):
return
field_cls
,
kwargs
# Create a read only field for model methods and properties.
def
build_nested_field
(
self
,
field_name
,
info
,
model
,
nested_depth
):
"""
Create nested fields for forward and reverse relationships.
"""
relation_info
=
info
.
relations
[
field_name
]
class
NestedSerializer
(
ModelSerializer
):
class
Meta
:
model
=
relation_info
.
related
depth
=
nested_depth
-
1
field_cls
=
NestedSerializer
kwargs
=
get_nested_relation_kwargs
(
relation_info
)
return
field_cls
,
kwargs
def
build_property_field
(
self
,
field_name
,
info
,
model
):
"""
Create a read only field for model methods and properties.
"""
field_cls
=
ReadOnlyField
field_cls
=
ReadOnlyField
kwargs
=
{}
kwargs
=
{}
elif
field_name
==
api_settings
.
URL_FIELD_NAME
:
return
field_cls
,
kwargs
# Create the URL field.
def
build_url_field
(
self
,
field_name
,
info
,
model
):
"""
Create a field representing the object's own URL.
"""
field_cls
=
HyperlinkedIdentityField
field_cls
=
HyperlinkedIdentityField
kwargs
=
get_url_kwargs
(
model
)
kwargs
=
get_url_kwargs
(
model
)
else
:
return
field_cls
,
kwargs
def
build_unknown_field
(
self
,
field_name
,
info
,
model
):
"""
Raise an error on any unknown fields.
"""
raise
ImproperlyConfigured
(
raise
ImproperlyConfigured
(
'Field name `
%
s` is not valid for model `
%
s`.'
%
'Field name `
%
s` is not valid for model `
%
s`.'
%
(
field_name
,
model
.
__class__
.
__name__
)
(
field_name
,
model
.
__class__
.
__name__
)
)
)
return
field_cls
,
kwargs
def
build_field_kwargs
(
self
,
kwargs
,
extra_kwargs
,
field_name
):
def
build_final_kwargs
(
self
,
kwargs
,
extra_kwargs
,
field_name
):
"""
"""
Include an 'extra_kwargs' that have been included for this field,
Include an 'extra_kwargs' that have been included for this field,
possibly removing any incompatible existing keyword arguments.
possibly removing any incompatible existing keyword arguments.
...
@@ -994,38 +1040,61 @@ class ModelSerializer(Serializer):
...
@@ -994,38 +1040,61 @@ class ModelSerializer(Serializer):
return
kwargs
return
kwargs
def
_get_model_fields
(
self
,
field_names
,
declared_fields
,
extra_kwargs
):
# Methods for determining additional keyword arguments to apply...
def
get_extra_kwargs
(
self
):
"""
"""
Returns all the model fields that are being mapped to by fields
Return a dictionary mapping field names to a dictionary of
on the serializer class.
additional keyword arguments.
Returned as a dict of 'model field name' -> 'model field'.
Used internally by `get_uniqueness_field_options`.
"""
"""
model
=
getattr
(
self
.
Meta
,
'model'
)
extra_kwargs
=
getattr
(
self
.
Meta
,
'extra_kwargs'
,
{})
model_fields
=
{}
for
field_name
in
field_names
:
read_only_fields
=
getattr
(
self
.
Meta
,
'read_only_fields'
,
None
)
if
field_name
in
declared_fields
:
if
read_only_fields
is
not
None
:
# If the field is declared on the serializer
for
field_name
in
read_only_fields
:
field
=
declared_fields
[
field_name
]
kwargs
=
extra_kwargs
.
get
(
field_name
,
{})
source
=
field
.
source
or
field_name
kwargs
[
'read_only'
]
=
True
else
:
extra_kwargs
[
field_name
]
=
kwargs
try
:
source
=
extra_kwargs
[
field_name
][
'source'
]
except
KeyError
:
source
=
field_name
if
'.'
in
source
or
source
==
'*'
:
# These are all pending deprecation.
# Model fields will always have a simple source mapping,
write_only_fields
=
getattr
(
self
.
Meta
,
'write_only_fields'
,
None
)
# they can't be nested attribute lookups.
if
write_only_fields
is
not
None
:
continue
warnings
.
warn
(
"The `Meta.write_only_fields` option is pending deprecation. "
"Use `Meta.extra_kwargs={<field_name>: {'write_only': True}}` instead."
,
PendingDeprecationWarning
,
stacklevel
=
3
)
for
field_name
in
write_only_fields
:
kwargs
=
extra_kwargs
.
get
(
field_name
,
{})
kwargs
[
'write_only'
]
=
True
extra_kwargs
[
field_name
]
=
kwargs
try
:
view_name
=
getattr
(
self
.
Meta
,
'view_name'
,
None
)
model_fields
[
source
]
=
model
.
_meta
.
get_field
(
source
)
if
view_name
is
not
None
:
except
FieldDoesNotExist
:
warnings
.
warn
(
pass
"The `Meta.view_name` option is pending deprecation. "
"Use `Meta.extra_kwargs={'url': {'view_name': ...}}` instead."
,
PendingDeprecationWarning
,
stacklevel
=
3
)
kwargs
=
extra_kwargs
.
get
(
api_settings
.
URL_FIELD_NAME
,
{})
kwargs
[
'view_name'
]
=
view_name
extra_kwargs
[
api_settings
.
URL_FIELD_NAME
]
=
kwargs
return
model_fields
lookup_field
=
getattr
(
self
.
Meta
,
'lookup_field'
,
None
)
if
lookup_field
is
not
None
:
warnings
.
warn
(
"The `Meta.lookup_field` option is pending deprecation. "
"Use `Meta.extra_kwargs={'url': {'lookup_field': ...}}` instead."
,
PendingDeprecationWarning
,
stacklevel
=
3
)
kwargs
=
extra_kwargs
.
get
(
api_settings
.
URL_FIELD_NAME
,
{})
kwargs
[
'lookup_field'
]
=
lookup_field
extra_kwargs
[
api_settings
.
URL_FIELD_NAME
]
=
kwargs
return
extra_kwargs
def
get_uniqueness_extra_kwargs
(
self
,
field_names
,
declared_fields
,
extra_kwargs
):
def
get_uniqueness_extra_kwargs
(
self
,
field_names
,
declared_fields
,
extra_kwargs
):
"""
"""
...
@@ -1102,140 +1171,127 @@ class ModelSerializer(Serializer):
...
@@ -1102,140 +1171,127 @@ class ModelSerializer(Serializer):
return
extra_kwargs
,
hidden_fields
return
extra_kwargs
,
hidden_fields
def
get_extra_kwargs
(
self
):
def
_get_model_fields
(
self
,
field_names
,
declared_fields
,
extra_kwargs
):
"""
"""
Return a dictionary mapping field names to a dictionary of
Returns all the model fields that are being mapped to by fields
additional keyword arguments.
on the serializer class.
Returned as a dict of 'model field name' -> 'model field'.
Used internally by `get_uniqueness_field_options`.
"""
"""
extra_kwargs
=
getattr
(
self
.
Meta
,
'extra_kwargs'
,
{})
model
=
getattr
(
self
.
Meta
,
'model'
)
model_fields
=
{}
read_only_fields
=
getattr
(
self
.
Meta
,
'read_only_fields'
,
None
)
for
field_name
in
field_names
:
if
read_only_fields
is
not
None
:
if
field_name
in
declared_fields
:
for
field_name
in
read_only_fields
:
# If the field is declared on the serializer
kwargs
=
extra_kwargs
.
get
(
field_name
,
{})
field
=
declared_fields
[
field_name
]
kwargs
[
'read_only'
]
=
True
source
=
field
.
source
or
field_name
extra_kwargs
[
field_name
]
=
kwargs
else
:
try
:
source
=
extra_kwargs
[
field_name
][
'source'
]
except
KeyError
:
source
=
field_name
# These are all pending deprecation.
if
'.'
in
source
or
source
==
'*'
:
write_only_fields
=
getattr
(
self
.
Meta
,
'write_only_fields'
,
None
)
# Model fields will always have a simple source mapping,
if
write_only_fields
is
not
None
:
# they can't be nested attribute lookups.
warnings
.
warn
(
continue
"The `Meta.write_only_fields` option is pending deprecation. "
"Use `Meta.extra_kwargs={<field_name>: {'write_only': True}}` instead."
,
PendingDeprecationWarning
,
stacklevel
=
3
)
for
field_name
in
write_only_fields
:
kwargs
=
extra_kwargs
.
get
(
field_name
,
{})
kwargs
[
'write_only'
]
=
True
extra_kwargs
[
field_name
]
=
kwargs
view_name
=
getattr
(
self
.
Meta
,
'view_name'
,
None
)
try
:
if
view_name
is
not
None
:
model_fields
[
source
]
=
model
.
_meta
.
get_field
(
source
)
warnings
.
warn
(
except
FieldDoesNotExist
:
"The `Meta.view_name` option is pending deprecation. "
pass
"Use `Meta.extra_kwargs={'url': {'view_name': ...}}` instead."
,
PendingDeprecationWarning
,
stacklevel
=
3
)
kwargs
=
extra_kwargs
.
get
(
api_settings
.
URL_FIELD_NAME
,
{})
kwargs
[
'view_name'
]
=
view_name
extra_kwargs
[
api_settings
.
URL_FIELD_NAME
]
=
kwargs
lookup_field
=
getattr
(
self
.
Meta
,
'lookup_field'
,
None
)
return
model_fields
if
lookup_field
is
not
None
:
warnings
.
warn
(
"The `Meta.lookup_field` option is pending deprecation. "
"Use `Meta.extra_kwargs={'url': {'lookup_field': ...}}` instead."
,
PendingDeprecationWarning
,
stacklevel
=
3
)
kwargs
=
extra_kwargs
.
get
(
api_settings
.
URL_FIELD_NAME
,
{})
kwargs
[
'lookup_field'
]
=
lookup_field
extra_kwargs
[
api_settings
.
URL_FIELD_NAME
]
=
kwargs
return
extra_kwargs
# Determine the validators to apply...
def
get_
field_names
(
self
,
declared_fields
,
info
):
def
get_
validators
(
self
):
"""
"""
Returns the list of all field names that should be created when
Determine the set of validators to use when instantiating serializer.
instantiating this serializer class. This is based on the default
set of fields, but also takes into account the `Meta.fields` or
`Meta.exclude` options if they have been specified.
"""
"""
fields
=
getattr
(
self
.
Meta
,
'fields'
,
None
)
# If the validators have been declared explicitly then use that.
exclude
=
getattr
(
self
.
Meta
,
'exclude'
,
None
)
validators
=
getattr
(
getattr
(
self
,
'Meta'
,
None
),
'validators'
,
None
)
if
validators
is
not
None
:
return
validators
if
fields
and
not
isinstance
(
fields
,
(
list
,
tuple
)):
# Otherwise use the default set of validators.
raise
TypeError
(
return
(
'The `fields` option must be a list or tuple. Got
%
s.'
%
self
.
get_unique_together_validators
()
+
type
(
fields
)
.
__name__
self
.
get_unique_for_date_validators
()
)
)
if
exclude
and
not
isinstance
(
exclude
,
(
list
,
tuple
)):
def
get_unique_together_validators
(
self
):
raise
TypeError
(
"""
'The `exclude` option must be a list or tuple. Got
%
s.'
%
Determine a default set of validators for any unique_together contraints.
type
(
exclude
)
.
__name__
"""
model_class_inheritance_tree
=
(
[
self
.
Meta
.
model
]
+
list
(
self
.
Meta
.
model
.
_meta
.
parents
.
keys
())
)
)
assert
not
(
fields
and
exclude
),
(
# The field names we're passing though here only include fields
"Cannot set both 'fields' and 'exclude' options on "
# which may map onto a model field. Any dotted field name lookups
"serializer {serializer_class}."
.
format
(
# cannot map to a field, and must be a traversal, so we're not
serializer_class
=
self
.
__class__
.
__name__
# including those.
)
field_names
=
set
([
)
field
.
source
for
field
in
self
.
fields
.
values
()
if
(
field
.
source
!=
'*'
)
and
(
'.'
not
in
field
.
source
)
])
if
fields
is
not
None
:
# Note that we make sure to check `unique_together` both on the
# Ensure that all declared fields have also been included in the
# base model class, but also on any parent classes.
# `Meta.fields` option.
validators
=
[]
for
field_name
in
declared_fields
:
for
parent_class
in
model_class_inheritance_tree
:
assert
field_name
in
fields
,
(
for
unique_together
in
parent_class
.
_meta
.
unique_together
:
"The field '{field_name}' was declared on serializer "
if
field_names
.
issuperset
(
set
(
unique_together
)):
"{serializer_class}, but has not been included in the "
validator
=
UniqueTogetherValidator
(
"'fields' option."
.
format
(
queryset
=
parent_class
.
_default_manager
,
field_name
=
field_name
,
fields
=
unique_together
serializer_class
=
self
.
__class__
.
__name__
)
)
)
return
fields
validators
.
append
(
validator
)
return
validators
# Use the default set of field names if `Meta.fields` is not specified.
def
get_unique_for_date_validators
(
self
):
fields
=
self
.
get_default_field_names
(
declared_fields
,
info
)
"""
Determine a default set of validators for the following contraints:
if
exclude
is
not
None
:
* unique_for_date
# If `Meta.exclude` is included, then remove those fields.
* unique_for_month
for
field_name
in
exclude
:
* unique_for_year
assert
field_name
in
fields
,
(
"""
"The field '{field_name}' was include on serializer "
info
=
model_meta
.
get_field_info
(
self
.
Meta
.
model
)
"{serializer_class} in the 'exclude' option, but does "
default_manager
=
self
.
Meta
.
model
.
_default_manager
"not match any model field."
.
format
(
field_names
=
[
field
.
source
for
field
in
self
.
fields
.
values
()]
field_name
=
field_name
,
serializer_class
=
self
.
__class__
.
__name__
)
)
fields
.
remove
(
field_name
)
return
fields
validators
=
[]
def
get_default_field_names
(
self
,
declared_fields
,
model_info
):
for
field_name
,
field
in
info
.
fields_and_pk
.
items
():
"""
if
field
.
unique_for_date
and
field_name
in
field_names
:
Return the default list of field names that will be used if the
validator
=
UniqueForDateValidator
(
`Meta.fields` option is not specified.
queryset
=
default_manager
,
"""
field
=
field_name
,
return
(
date_field
=
field
.
unique_for_date
[
model_info
.
pk
.
name
]
+
list
(
declared_fields
.
keys
())
+
list
(
model_info
.
fields
.
keys
())
+
list
(
model_info
.
forward_relations
.
keys
())
)
)
validators
.
append
(
validator
)
def
_get_nested_class
(
self
,
nested_depth
,
relation_info
):
if
field
.
unique_for_month
and
field_name
in
field_names
:
class
NestedSerializer
(
ModelSerializer
):
validator
=
UniqueForMonthValidator
(
class
Meta
:
queryset
=
default_manager
,
model
=
relation_info
.
related
field
=
field_name
,
depth
=
nested_depth
-
1
date_field
=
field
.
unique_for_month
)
validators
.
append
(
validator
)
return
NestedSerializer
if
field
.
unique_for_year
and
field_name
in
field_names
:
validator
=
UniqueForYearValidator
(
queryset
=
default_manager
,
field
=
field_name
,
date_field
=
field
.
unique_for_year
)
validators
.
append
(
validator
)
return
validators
class
HyperlinkedModelSerializer
(
ModelSerializer
):
class
HyperlinkedModelSerializer
(
ModelSerializer
):
...
@@ -1246,7 +1302,7 @@ class HyperlinkedModelSerializer(ModelSerializer):
...
@@ -1246,7 +1302,7 @@ class HyperlinkedModelSerializer(ModelSerializer):
* A 'url' field is included instead of the 'id' field.
* A 'url' field is included instead of the 'id' field.
* Relationships to other instances are hyperlinks, instead of primary keys.
* Relationships to other instances are hyperlinks, instead of primary keys.
"""
"""
_related_class
=
HyperlinkedRelatedField
serializer
_related_class
=
HyperlinkedRelatedField
def
get_default_field_names
(
self
,
declared_fields
,
model_info
):
def
get_default_field_names
(
self
,
declared_fields
,
model_info
):
"""
"""
...
@@ -1260,10 +1316,17 @@ class HyperlinkedModelSerializer(ModelSerializer):
...
@@ -1260,10 +1316,17 @@ class HyperlinkedModelSerializer(ModelSerializer):
list
(
model_info
.
forward_relations
.
keys
())
list
(
model_info
.
forward_relations
.
keys
())
)
)
def
_get_nested_class
(
self
,
nested_depth
,
relation_info
):
def
build_nested_field
(
self
,
field_name
,
info
,
model
,
nested_depth
):
"""
Create nested fields for forward and reverse relationships.
"""
relation_info
=
info
.
relations
[
field_name
]
class
NestedSerializer
(
HyperlinkedModelSerializer
):
class
NestedSerializer
(
HyperlinkedModelSerializer
):
class
Meta
:
class
Meta
:
model
=
relation_info
.
related
model
=
relation_info
.
related
depth
=
nested_depth
-
1
depth
=
nested_depth
-
1
return
NestedSerializer
field_cls
=
NestedSerializer
kwargs
=
get_nested_relation_kwargs
(
relation_info
)
return
field_cls
,
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