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
8586290d
Commit
8586290d
authored
Nov 19, 2014
by
Tom Christie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Apply defaults and requiredness to unique_together fields. Closes #2092.
parent
6cb65101
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
64 additions
and
37 deletions
+64
-37
rest_framework/serializers.py
+49
-34
rest_framework/validators.py
+13
-1
tests/test_validators.py
+2
-2
No files found.
rest_framework/serializers.py
View file @
8586290d
...
...
@@ -720,49 +720,60 @@ class ModelSerializer(Serializer):
# Determine if we need any additional `HiddenField` or extra keyword
# arguments to deal with `unique_for` dates that are required to
# be in the input data in order to validate it.
unique_fields
=
{}
hidden_fields
=
{}
for
model_field_name
,
field_name
in
model_field_mapping
.
items
():
try
:
model_field
=
model
.
_meta
.
get_field
(
model_field_name
)
except
FieldDoesNotExist
:
continue
#
Deal with each of the `unique_for_*` cas
es.
for
date_field_name
in
(
#
Include each of the `unique_for_*` field nam
es.
unique_constraint_names
=
set
([
model_field
.
unique_for_date
,
model_field
.
unique_for_month
,
model_field
.
unique_for_year
):
if
date_field_name
is
None
:
continue
# Get the model field that is refered too.
date_field
=
model
.
_meta
.
get_field
(
date_field_name
)
if
date_field
.
auto_now_add
:
default
=
CreateOnlyDefault
(
timezone
.
now
)
elif
date_field
.
auto_now
:
default
=
timezone
.
now
elif
date_field
.
has_default
():
default
=
model_field
.
default
else
:
default
=
empty
if
date_field_name
in
model_field_mapping
:
# The corresponding date field is present in the serializer
if
date_field_name
not
in
extra_kwargs
:
extra_kwargs
[
date_field_name
]
=
{}
if
default
is
empty
:
if
'required'
not
in
extra_kwargs
[
date_field_name
]:
extra_kwargs
[
date_field_name
][
'required'
]
=
True
else
:
if
'default'
not
in
extra_kwargs
[
date_field_name
]:
extra_kwargs
[
date_field_name
][
'default'
]
=
default
])
unique_constraint_names
-=
set
([
None
])
# Include each of the `unique_together` field names,
# so long as all the field names are included on the serializer.
for
parent_class
in
[
model
]
+
list
(
model
.
_meta
.
parents
.
keys
()):
for
unique_together_list
in
parent_class
.
_meta
.
unique_together
:
if
set
(
fields
)
.
issuperset
(
set
(
unique_together_list
)):
unique_constraint_names
|=
set
(
unique_together_list
)
# Now we have all the field names that have uniqueness constraints
# applied, we can add the extra 'required=...' or 'default=...'
# arguments that are appropriate to these fields, or add a `HiddenField` for it.
for
unique_constraint_name
in
unique_constraint_names
:
# Get the model field that is refered too.
unique_constraint_field
=
model
.
_meta
.
get_field
(
unique_constraint_name
)
if
getattr
(
unique_constraint_field
,
'auto_now_add'
,
None
):
default
=
CreateOnlyDefault
(
timezone
.
now
)
elif
getattr
(
unique_constraint_field
,
'auto_now'
,
None
):
default
=
timezone
.
now
elif
unique_constraint_field
.
has_default
():
default
=
model_field
.
default
else
:
default
=
empty
if
unique_constraint_name
in
model_field_mapping
:
# The corresponding field is present in the serializer
if
unique_constraint_name
not
in
extra_kwargs
:
extra_kwargs
[
unique_constraint_name
]
=
{}
if
default
is
empty
:
if
'required'
not
in
extra_kwargs
[
unique_constraint_name
]:
extra_kwargs
[
unique_constraint_name
][
'required'
]
=
True
else
:
# The corresponding date field is not present in the,
# serializer. We have a default to use for the date, so
# add in a hidden field that populates it.
unique_fields
[
date_field_name
]
=
HiddenField
(
default
=
default
)
if
'default'
not
in
extra_kwargs
[
unique_constraint_name
]:
extra_kwargs
[
unique_constraint_name
][
'default'
]
=
default
elif
default
is
not
empty
:
# The corresponding field is not present in the,
# serializer. We have a default to use for it, so
# add in a hidden field that populates it.
hidden_fields
[
unique_constraint_name
]
=
HiddenField
(
default
=
default
)
# Now determine the fields that should be included on the serializer.
for
field_name
in
fields
:
...
...
@@ -838,12 +849,16 @@ class ModelSerializer(Serializer):
'validators'
,
'queryset'
]:
kwargs
.
pop
(
attr
,
None
)
if
extras
.
get
(
'default'
)
and
kwargs
.
get
(
'required'
)
is
False
:
kwargs
.
pop
(
'required'
)
kwargs
.
update
(
extras
)
# Create the serializer field.
ret
[
field_name
]
=
field_cls
(
**
kwargs
)
for
field_name
,
field
in
unique
_fields
.
items
():
for
field_name
,
field
in
hidden
_fields
.
items
():
ret
[
field_name
]
=
field
return
ret
...
...
rest_framework/validators.py
View file @
8586290d
...
...
@@ -93,6 +93,9 @@ class UniqueTogetherValidator:
The `UniqueTogetherValidator` always forces an implied 'required'
state on the fields it applies to.
"""
if
self
.
instance
is
not
None
:
return
missing
=
dict
([
(
field_name
,
self
.
missing_message
)
for
field_name
in
self
.
fields
...
...
@@ -105,8 +108,17 @@ class UniqueTogetherValidator:
"""
Filter the queryset to all instances matching the given attributes.
"""
# If this is an update, then any unprovided field should
# have it's value set based on the existing instance attribute.
if
self
.
instance
is
not
None
:
for
field_name
in
self
.
fields
:
if
field_name
not
in
attrs
:
attrs
[
field_name
]
=
getattr
(
self
.
instance
,
field_name
)
# Determine the filter keyword arguments and filter the queryset.
filter_kwargs
=
dict
([
(
field_name
,
attrs
[
field_name
])
for
field_name
in
self
.
fields
(
field_name
,
attrs
[
field_name
])
for
field_name
in
self
.
fields
])
return
queryset
.
filter
(
**
filter_kwargs
)
...
...
tests/test_validators.py
View file @
8586290d
...
...
@@ -88,8 +88,8 @@ class TestUniquenessTogetherValidation(TestCase):
expected
=
dedent
(
"""
UniquenessTogetherSerializer():
id = IntegerField(label='ID', read_only=True)
race_name = CharField(max_length=100)
position = IntegerField()
race_name = CharField(max_length=100
, required=True
)
position = IntegerField(
required=True
)
class Meta:
validators = [<UniqueTogetherValidator(queryset=UniquenessTogetherModel.objects.all(), fields=('race_name', 'position'))>]
"""
)
...
...
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