def _validate_model_type(api_field_name, model_field, django_field_type,
loc=()):
"""
Checks that the type of the specified model field matches with the
`django_field_type` passed as parameter.
`django_field_type` may be an iterable of types. If at least one type
matches with the type of given model field, then we have a match.
"""
if isinstance(django_field_type, Iterable):
matches = any(isinstance(model_field, d_field)
for d_field in django_field_type)
else:
matches = isinstance(model_field, django_field_type)
if not matches:
raise utils.DRFAdapterException(
'Field {!r} is not a {!r} in your django model'.format(
api_field_name, django_field_type), loc=loc)
return model_field
python类Field()的实例源码
def test_should_base_field_convert_string():
assert_conversion(serializers.Field, graphene.String)
def test_should_model_convert_field():
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = None
fields = '__all__'
assert_conversion(MyModelSerializer, graphene.Field, is_input=False)
def get_view_name(self):
return "Field Choices"
#
# Mixins
#
def default_field_constructor(self, instance, spec, loc, context,
predicate_type):
"""
A common constructor for the drf fields.
There are two cases:
* If the field is a model field, then it does not initialize a
`serializers.Field` object, but it stores all its properties in
dictionary in order to be initialized later from the serializer.
* If the field is a non-model field or its type is either `.struct`
or `.structarry`, then the corresponding `serializers.Field` is
contructed.
Moreover, this method checks if the field conforms to the model
configuations before being constructed.
"""
model, automated = self.validate_model_configuration(
instance, spec, loc, context, predicate_type)
path = (self.ADAPTER_CONF,)
instance_source = spec.pop('instance_source', None)
onmodel = spec.get('onmodel', True)
if instance_source and onmodel:
raise utils.DRFAdapterException(
'`instance_source` and `onmodel=True` are mutually'
' exclusive.', loc=loc)
field_kwargs = {k: v for k, v in spec.iteritems() if k != 'onmodel'}
field_kwargs.update(doc.doc_get(instance, path) or {})
field_kwargs.update(self._get_extra_field_kwargs(
predicate_type, instance, loc, context, automated, field_kwargs))
doc.doc_set(instance, (self.ADAPTER_CONF, 'source'), instance_source)
drf_field = self._generate_field(
instance, context.get('parent_name'), predicate_type, model,
automated and onmodel, **field_kwargs)
doc.doc_set(instance, (self.ADAPTER_CONF, 'field'), drf_field)
return instance
def extract_related_model(self, related_field, django_conf, loc=()):
"""
Extracts related model based on given field. It also checks that
given field is related to another model.
"""
model = self.extract_model(related_field, django_conf, loc)
related_field = model._meta.get_field(related_field)
if related_field.related_model is None:
raise utils.DRFAdapterException(
'Field {!r} is not related with another model'.format(
related_field), loc=loc)
return related_field.related_model
def get_default(self):
"""
Override `get_default()` defined on `serializers.Field` class.
In this case, if there are empty data for a serializer field, i.e.
a nested field, try to populate it by retrieving the default value of
each of their fields.
"""
default = {}
for k, v in self.fields.iteritems():
try:
default[k] = v.get_default()
except serializers.SkipField:
pass
return default
def classify_model_fields(model_fields):
""" Seperate already initialized drf_fields from the rest. """
drf_fields = {}
field_properties = {}
for field_name, value in model_fields.iteritems():
if isinstance(value, serializers.Field):
drf_fields[field_name] = value
else:
assert isinstance(value, dict), (
'A dictionary of serializer field properties is expected.'
' A {!r} found'.format(str(type(value))))
field_properties[field_name] = value
return field_properties, drf_fields
def modelserializer_factory(model, serializer=serializers.ModelSerializer, fields=None, exclude=None, **kwargs):
"""
Generate serializer basing on django's modelform_factory
:param model: model we create serializer for
:param serializer: base serializer class
:param fields: list of fields to include in serializer
:param exclude: list of fields to exclude from serializer
:param kwargs: fields mapping
:return:
"""
# TODO: decide if we need cache and what to do with parameters tha can be different
serializer_class = serializer_cache.get(model, None)
if serializer_class:
return serializer_class
def _get_declared_fields(attrs):
fields = [(field_name, attrs.pop(field_name))
for field_name, obj in list(attrs.items())
if isinstance(obj, serializers.Field)]
fields.sort(key=lambda x: x[1]._creation_counter)
return OrderedDict(fields)
meta_attrs = {'model': model}
if fields is not None:
meta_attrs['fields'] = fields
if exclude is not None:
meta_attrs['exclude'] = exclude
if fields is None and exclude is None:
meta_attrs['fields'] = '__all__'
parent = (object, )
Meta = type(str('Meta'), parent, meta_attrs)
class_name = model.__name__ + str('Serializer')
serializer_class_attrs = {
'Meta': Meta,
'_get_declared_fields': _get_declared_fields(kwargs),
}
serializer_class = type(serializer)(class_name, (serializer,), serializer_class_attrs)
serializer_cache[model] = serializer_class
return serializer_class