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)
Ejemplo n.º 6
0
    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