def test_get_embed_model_field_info(self, embed_container, embedded): """ Tests that embedded model fields are correctly caught and managed """ field_info = meta_manager.get_field_info(embed_container) # Confirm that embedded model info was caught correctly embed_field_info = field_info.embedded['embed_field'] assert embed_field_info.model_field.model_container == embedded.__class__ assert not embed_field_info.is_array
def test_get_mtm_relation_field_info(self, base_relation, reverse_relation): """ Tests that many-to-many relation information is correctly sorted and managed by the get_field_info() function """ field_info = meta_manager.get_field_info(base_relation) # Confirm that the one-to-many relation was handled correctly mtm_field_info = field_info.relations['mtm_field'] assert isinstance(mtm_field_info.model_field, djm_models.ManyToManyField) assert mtm_field_info.related_model == reverse_relation.__class__ assert mtm_field_info.to_many # Many-to-Many fields lack a `to_field` parameter assert not mtm_field_info.has_through_model assert not mtm_field_info.reverse
def test_get_fk_relation_field_info(self, foreign_relation, base_relation): """ Tests that one-to-many relation information is correctly sorted and managed by the get_field_info() function """ field_info = meta_manager.get_field_info(base_relation) # Confirm that one-to-many relations are handled correctly fk_field_info = field_info.relations['fk_field'] assert isinstance(fk_field_info.model_field, djm_models.ForeignKey) assert fk_field_info.related_model == foreign_relation.__class__ assert not fk_field_info.to_many assert (fk_field_info.to_field == '_id') assert not fk_field_info.has_through_model assert not fk_field_info.reverse
def test_get_field_info_unique_pk(self, object_id): """ Confirm that, if the pk is explicitly set in a model, it is caught and sorted correctly when fetching field info for said model """ field_info = meta_manager.get_field_info(object_id) # Confirm that the user specified PK was caught assert field_info.pk.name == '_id' # Custom name specified by user assert isinstance(field_info.pk, djm_models.ObjectIdField) # Confirm that the unique pk is still excluded from the fields assert '_id' not in field_info.fields # Confirm that said pk is still caught in fields_and_pk assert '_id' in field_info.fields_and_pk assert field_info.fields_and_pk['pk'].name == '_id'
def test_get_generic_model_field_info(self, generic): """ Confirm that models with only basic field types are properly managed """ field_info = meta_manager.get_field_info(generic) # Confirm that the automatically generated 'pk' field was captured assert field_info.pk.name == 'id' assert isinstance(field_info.pk, djm_models.AutoField) # Confirm field types were caught correctly field_type_dict = { 'big_int': djm_models.BigIntegerField, 'bool': djm_models.BooleanField, 'char': djm_models.CharField, 'comma_int': djm_models.CommaSeparatedIntegerField, 'date': djm_models.DateField, 'date_time': djm_models.DateTimeField, 'decimal': djm_models.DecimalField, 'email': djm_models.EmailField, 'float': djm_models.FloatField, 'integer': djm_models.IntegerField, 'null_bool': djm_models.NullBooleanField, 'pos_int': djm_models.PositiveIntegerField, 'pos_small_int': djm_models.PositiveSmallIntegerField, 'slug': djm_models.SlugField, 'small_int': djm_models.SmallIntegerField, 'text': djm_models.TextField, 'time': djm_models.TimeField, 'url': djm_models.URLField, 'ip': djm_models.GenericIPAddressField, 'uuid': djm_models.UUIDField, } for key, val in field_type_dict.items(): assert isinstance(field_info.fields[key], val) # Confirm that the `fields_and_pk` parameter was built correctly field_and_pk_type_dict = { 'pk': djm_models.AutoField, 'id': djm_models.AutoField, 'big_int': djm_models.BigIntegerField, 'bool': djm_models.BooleanField, 'char': djm_models.CharField, 'comma_int': djm_models.CommaSeparatedIntegerField, 'date': djm_models.DateField, 'date_time': djm_models.DateTimeField, 'decimal': djm_models.DecimalField, 'email': djm_models.EmailField, 'float': djm_models.FloatField, 'integer': djm_models.IntegerField, 'null_bool': djm_models.NullBooleanField, 'pos_int': djm_models.PositiveIntegerField, 'pos_small_int': djm_models.PositiveSmallIntegerField, 'slug': djm_models.SlugField, 'small_int': djm_models.SmallIntegerField, 'text': djm_models.TextField, 'time': djm_models.TimeField, 'url': djm_models.URLField, 'ip': djm_models.GenericIPAddressField, 'uuid': djm_models.UUIDField, } for key, val in field_and_pk_type_dict.items(): assert isinstance(field_info.fields_and_pk[key], val)
def get_fields(self): """ An override of DRF's `get_fields` to enable EmbeddedModelFields to be correctly caught and constructed """ if self.url_field_name is None: self.url_field_name = api_settings.URL_FIELD_NAME assert hasattr(self, 'Meta'), ( 'Class {serializer_class} missing "Meta" attribute'.format( serializer_class=self.__class__.__name__)) assert hasattr(self.Meta, 'model'), ( "Class {serializer_name} missing `Meta.model` attribute".format( serializer_name=self.__class__.__name__)) if meta_manager.is_model_abstract( self.Meta.model) and self._saving_instances: raise ValueError( "Cannot use DjongoModelSerializer w/ Abstract Models.\n" "Consider using an EmbeddedModelSerializer instead.") # Fetch and check useful metadata parameters declared_fields = copy.deepcopy(self._declared_fields) model = getattr(self.Meta, 'model') rel_depth = getattr(self.Meta, 'depth', 0) emb_depth = getattr(self.Meta, 'embed_depth', 5) assert rel_depth >= 0, "'depth' may not be negative" assert rel_depth <= 10, "'depth' may not be greater than 10" assert emb_depth >= 0, "'embed_depth' may not be negative" # Fetch information about the fields for our model class info = meta_manager.get_field_info(model) field_names = self.get_field_names(declared_fields, info) # Determine extra field arguments + hidden fields that need to # be included extra_kwargs = self.get_extra_kwargs() extra_kwargs, hidden_fields = self.get_uniqueness_extra_kwargs( field_names, declared_fields, extra_kwargs) # Find fields which are required for the serializer fields = {} for field_name in field_names: # Fields explicitly declared should always be used if field_name in declared_fields: fields[field_name] = declared_fields[field_name] continue extra_field_kwargs = extra_kwargs.get(field_name, {}) source = extra_field_kwargs.get('source', field_name) if source == '*': source = field_name # Determine field class and keyword arguments field_class, field_kwargs = self.build_field( source, info, model, rel_depth, emb_depth) # Fetch any extra_kwargs specified by the meta field_kwargs = self.include_extra_kwargs(field_kwargs, extra_field_kwargs) # Create the serializer field fields[field_name] = field_class(**field_kwargs) # Update with any hidden fields fields.update(hidden_fields) return fields