def serializer_factory(endpoint=None, fields=None, base_class=None, model=None):
if model is not None:
assert endpoint is None, "You cannot specify both a model and an endpoint"
from .endpoints import Endpoint
endpoint = Endpoint(model=model)
else:
assert endpoint is not None, "You have to specify either a model or an endpoint"
if base_class is None:
base_class = endpoint.base_serializer
meta_attrs = {
'model': endpoint.model,
'fields': fields if fields is not None else endpoint.get_fields_for_serializer()
}
meta_parents = (object, )
if hasattr(base_class, 'Meta'):
meta_parents = (base_class.Meta, ) + meta_parents
Meta = type('Meta', meta_parents, meta_attrs)
cls_name = '{}Serializer'.format(endpoint.model.__name__)
cls_attrs = {
'Meta': Meta,
}
for meta_field in meta_attrs['fields']:
if meta_field not in base_class._declared_fields:
try:
model_field = endpoint.model._meta.get_field(meta_field)
if isinstance(model_field, OneToOneRel):
cls_attrs[meta_field] = serializers.PrimaryKeyRelatedField(read_only=True)
elif isinstance(model_field, ManyToOneRel):
cls_attrs[meta_field] = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
except FieldDoesNotExist:
cls_attrs[meta_field] = serializers.ReadOnlyField()
return type(cls_name, (NullToDefaultMixin, base_class, ), cls_attrs)
python类PrimaryKeyRelatedField()的实例源码
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for i in range(1, settings.STECHEC_NPLAYERS + 1):
f = serializers.PrimaryKeyRelatedField(queryset=models.Champion.objects.all(), write_only=True)
self.fields['champion_%d' % i] = f
if settings.STECHEC_USE_MAPS:
self.fields['map'] = serializers.PrimaryKeyRelatedField(queryset=models.Map.objects.all(), write_only=True)
def _extract_field_info(self, model, field_name, field, fields, relationships, adapter, target_app, allow_recursion=False):
if field_name == 'id':
return None
field_item = {
'name': field_name,
'type': adapter.field_type_mapping[field.__class__.__name__]
}
if isinstance(field, PrimaryKeyRelatedField) or isinstance(field, ManyRelatedField) \
or isinstance(field, ModelSerializer):
if model is None:
field_item['related_model'] = field.queryset.model._meta.model_name.lower()
field_item['app'] = target_app if target_app is not None else \
field.queryset.model._meta.app_label.lower()
relationships.append(field_item)
else:
model_field = model._meta.get_field(field_name)
field_item['related_model'] = model_field.related_model._meta.model_name.lower()
field_item['app'] = target_app if target_app is not None else \
model_field.related_model._meta.app_label.lower()
relationships.append(field_item)
if hasattr(model_field, 'field'):
field_item['inverse'] = model_field.field.name
elif hasattr(model_field, 'remote_field') and \
getattr(model_field.remote_field, 'related_name', None) is not None:
field_item['inverse'] = model_field.remote_field.related_name
if field_item.get('inverse', '-')[-1] == '+':
field_item.pop('inverse')
if isinstance(field, ModelSerializer):
if hasattr(field, 'many') and field.many:
field_item['type'] = adapter.field_type_mapping['ManyRelatedField']
else:
field_item['type'] = adapter.field_type_mapping['PrimaryKeyRelatedField']
elif isinstance(field, ModelSerializer):
field_item['related_model'] = field.queryset.model._meta.model_name.lower()
field_item['app'] = target_app if target_app is not None else \
field.queryset.model._meta.app_label.lower()
relationships.append(field_item)
if field.many:
field_item['type'] = adapter.field_type_mapping['ManyRelatedField']
else:
field_item['type'] = adapter.field_type_mapping['PrimaryKeyRelatedField']
elif isinstance(field, ListSerializer):
child_rels = []
child_fields = []
self._extract_field_info(model, field_name, field.child, child_fields, child_rels, adapter, target_app)
if len(child_rels) > 0:
for item in child_rels:
item['type'] = adapter.field_type_mapping['ManyRelatedField']
item.pop('inverse', None)
relationships.append(item)
else:
field_item['type'] = adapter.field_type_mapping('ListField')
fields.append(field_item)
else:
fields.append(field_item)
return field_item