mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-01-23 15:54:16 +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.
|
||||
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()
|
||||
|
||||
# Determine the set of model fields, and the fields that they map to.
|
||||
# We actually only need this to deal with the slightly awkward case
|
||||
# of supporting `unique_for_date`/`unique_for_month`/`unique_for_year`.
|
||||
model_field_mapping = {}
|
||||
for field_name in fields:
|
||||
if field_name in declared_fields:
|
||||
field = declared_fields[field_name]
|
||||
source = field.source or field_name
|
||||
model_fields = self.get_model_fields(field_names, declared_fields, extra_kwargs)
|
||||
uniqueness_extra_kwargs, hidden_fields = self.get_uniqueness_field_options(field_names, model_fields)
|
||||
for key, value in uniqueness_extra_kwargs.items():
|
||||
if key in extra_kwargs:
|
||||
extra_kwargs[key].update(value)
|
||||
else:
|
||||
try:
|
||||
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)
|
||||
extra_kwargs[key] = value
|
||||
|
||||
# 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:
|
||||
# Field is explicitly declared on the class, use that.
|
||||
ret[field_name] = declared_fields[field_name]
|
||||
|
@ -1046,6 +976,94 @@ class ModelSerializer(Serializer):
|
|||
|
||||
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):
|
||||
"""
|
||||
Return a dictionary mapping field names to a dictionary of
|
||||
|
|
Loading…
Reference in New Issue
Block a user