mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-02-02 20:54:42 +03:00
get_uniqueness_field_options first pass
This commit is contained in:
parent
1a84943a00
commit
caa1318124
|
@ -888,89 +888,19 @@ class ModelSerializer(Serializer):
|
||||||
# Retrieve metadata about fields & relationships on the model class.
|
# Retrieve metadata about fields & relationships on the model class.
|
||||||
info = model_meta.get_field_info(model)
|
info = model_meta.get_field_info(model)
|
||||||
|
|
||||||
fields = self.get_field_names(declared_fields, info)
|
field_names = self.get_field_names(declared_fields, info)
|
||||||
extra_kwargs = self.get_extra_kwargs()
|
extra_kwargs = self.get_extra_kwargs()
|
||||||
|
|
||||||
# Determine the set of model fields, and the fields that they map to.
|
model_fields = self.get_model_fields(field_names, declared_fields, extra_kwargs)
|
||||||
# We actually only need this to deal with the slightly awkward case
|
uniqueness_extra_kwargs, hidden_fields = self.get_uniqueness_field_options(field_names, model_fields)
|
||||||
# of supporting `unique_for_date`/`unique_for_month`/`unique_for_year`.
|
for key, value in uniqueness_extra_kwargs.items():
|
||||||
model_field_mapping = {}
|
if key in extra_kwargs:
|
||||||
for field_name in fields:
|
extra_kwargs[key].update(value)
|
||||||
if field_name in declared_fields:
|
|
||||||
field = declared_fields[field_name]
|
|
||||||
source = field.source or field_name
|
|
||||||
else:
|
else:
|
||||||
try:
|
extra_kwargs[key] = value
|
||||||
source = extra_kwargs[field_name]['source']
|
|
||||||
except KeyError:
|
|
||||||
source = field_name
|
|
||||||
# Model fields will always have a simple source mapping,
|
|
||||||
# they can't be nested attribute lookups.
|
|
||||||
if '.' not in source and source != '*':
|
|
||||||
model_field_mapping[source] = field_name
|
|
||||||
|
|
||||||
# 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.
|
|
||||||
hidden_fields = {}
|
|
||||||
unique_constraint_names = set()
|
|
||||||
|
|
||||||
for model_field_name, field_name in model_field_mapping.items():
|
|
||||||
try:
|
|
||||||
model_field = model._meta.get_field(model_field_name)
|
|
||||||
except FieldDoesNotExist:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Include each of the `unique_for_*` field names.
|
|
||||||
unique_constraint_names |= set([
|
|
||||||
model_field.unique_for_date,
|
|
||||||
model_field.unique_for_month,
|
|
||||||
model_field.unique_for_year
|
|
||||||
])
|
|
||||||
|
|
||||||
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 referred 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 = unique_constraint_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:
|
|
||||||
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.
|
# Now determine the fields that should be included on the serializer.
|
||||||
for field_name in fields:
|
for field_name in field_names:
|
||||||
if field_name in declared_fields:
|
if field_name in declared_fields:
|
||||||
# Field is explicitly declared on the class, use that.
|
# Field is explicitly declared on the class, use that.
|
||||||
ret[field_name] = declared_fields[field_name]
|
ret[field_name] = declared_fields[field_name]
|
||||||
|
@ -1046,6 +976,94 @@ class ModelSerializer(Serializer):
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
def get_model_fields(self, field_names, declared_fields, extra_kwargs):
|
||||||
|
# Returns all the model fields that are being mapped to by fields
|
||||||
|
# on the serializer class.
|
||||||
|
# Returned as a dict of 'model field name' -> 'model field'
|
||||||
|
model = getattr(self.Meta, 'model')
|
||||||
|
model_fields = {}
|
||||||
|
|
||||||
|
for field_name in field_names:
|
||||||
|
if field_name in declared_fields:
|
||||||
|
# If the field is declared on the serializer
|
||||||
|
field = declared_fields[field_name]
|
||||||
|
source = field.source or field_name
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
source = extra_kwargs[field_name]['source']
|
||||||
|
except KeyError:
|
||||||
|
source = field_name
|
||||||
|
|
||||||
|
if '.' in source or source == '*':
|
||||||
|
# Model fields will always have a simple source mapping,
|
||||||
|
# they can't be nested attribute lookups.
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
model_fields[source] = model._meta.get_field(source)
|
||||||
|
except FieldDoesNotExist:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return model_fields
|
||||||
|
|
||||||
|
def get_uniqueness_field_options(self, field_names, model_fields):
|
||||||
|
model = getattr(self.Meta, 'model')
|
||||||
|
|
||||||
|
# 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_constraint_names = set()
|
||||||
|
|
||||||
|
for model_field in model_fields.values():
|
||||||
|
# Include each of the `unique_for_*` field names.
|
||||||
|
unique_constraint_names |= set([
|
||||||
|
model_field.unique_for_date,
|
||||||
|
model_field.unique_for_month,
|
||||||
|
model_field.unique_for_year
|
||||||
|
])
|
||||||
|
|
||||||
|
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(field_names).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.
|
||||||
|
hidden_fields = {}
|
||||||
|
extra_kwargs = {}
|
||||||
|
|
||||||
|
for unique_constraint_name in unique_constraint_names:
|
||||||
|
# Get the model field that is referred 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 = unique_constraint_field.default
|
||||||
|
else:
|
||||||
|
default = empty
|
||||||
|
|
||||||
|
if unique_constraint_name in model_fields:
|
||||||
|
# The corresponding field is present in the serializer
|
||||||
|
if default is empty:
|
||||||
|
extra_kwargs[unique_constraint_name] = {'required': True}
|
||||||
|
else:
|
||||||
|
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)
|
||||||
|
|
||||||
|
return extra_kwargs, hidden_fields
|
||||||
|
|
||||||
def get_extra_kwargs(self):
|
def get_extra_kwargs(self):
|
||||||
"""
|
"""
|
||||||
Return a dictionary mapping field names to a dictionary of
|
Return a dictionary mapping field names to a dictionary of
|
||||||
|
|
Loading…
Reference in New Issue
Block a user