Beispiel #1
0
    def test_columnInfo(self):
        info = meta.model_info(Vehicle)

        col = info.primary_keys["id"]
        self.assertEqual(col.name, "id")
        self.assertDictEqual({"label": "Id", "help_text": "The primary key", "required": True}, col.field_kwargs)

        col = info.properties["type"]
        self.assertDictEqual(
            {"enum_class": VehicleType, "help_text": None, "label": "Type", "max_length": 3, "required": True},
            col.field_kwargs,
        )

        col = info.properties["paint"]
        self.assertDictEqual(
            {"choices": COLORS, "help_text": None, "label": "Paint", "max_length": 6, "required": False},
            col.field_kwargs,
        )
        self.assertEqual(col.parent_model, Vehicle)
        self.assertEqual(repr(col), "<column_info(Vehicle.paint)>")

        info = meta.model_info(AllKindsOfFields)
        col = info.properties["decimal"]
        self.assertDictEqual(
            {"decimal_places": None, "help_text": None, "label": "Decimal", "max_digits": None, "required": False},
            col.field_kwargs,
        )
Beispiel #2
0
    def test_app(self):
        info = meta.model_info(Owner)
        self.assertIs(info.app_config,
                      apps.get_containing_app_config(Owner.__module__))

        info = meta.model_info(OtherAppInOtherApp)
        self.assertIs(info.app_config,
                      apps.get_containing_app_config(Owner.__module__))
Beispiel #3
0
    def test_primary_keys_from_dict(self):
        info = meta.model_info(Owner)

        key = info.primary_keys_from_dict({"id": 1})
        self.assertEqual(key, 1)

        info = meta.model_info(CompositePkModel)
        key = info.primary_keys_from_dict({"id": 1, "pk": 2})
        self.assertEqual(key, (1, 2))
Beispiel #4
0
    def test_model_meta(self):
        info = meta.model_info(Business)

        info_from_meta = meta.model_info(Business.__mapper__)

        info_from_instance = meta.model_info(Business())

        self.assertIs(info, info_from_meta)
        self.assertIs(info_from_meta, info_from_instance)
Beispiel #5
0
    def test_reprs(self):
        owner_info = meta.model_info(Owner)
        self.assertEqual(
            repr(owner_info),
            "\n".join(
                [
                    "<model_info(Owner)>",
                    "    <integer_column_info(Owner.id) pk>",
                    "    <string_column_info(Owner.first_name)>",
                    "    <string_column_info(Owner.last_name)>",
                    "    <relation_info(Owner.vehicles)>",
                ]
            ),
        )

        vehicle_info = meta.model_info(Vehicle)
        self.assertEqual(
            repr(vehicle_info),
            "\n".join(
                [
                    "<model_info(Vehicle)>",
                    "    <integer_column_info(Vehicle.id) pk>",
                    "    <integer_column_info(Vehicle._owner_id)>",
                    "    <datetime_column_info(Vehicle.created_at)>",
                    "    <boolean_column_info(Vehicle.is_used)>",
                    "    <numeric_column_info(Vehicle.msrp)>",
                    "    <string_column_info(Vehicle.name)>",
                    "    <choice_column_info(Vehicle.paint)>",
                    "    <enum_column_info(Vehicle.type)>",
                    "    <relation_info(Vehicle.options)>",
                    "    <relation_info(Vehicle.owner)>",
                    "    <relation_info(Vehicle.parts)>",
                ]
            ),
        )
        business_info = meta.model_info(Business)
        self.assertEqual(
            repr(business_info),
            "\n".join(
                [
                    "<model_info(Business)>",
                    "    <integer_column_info(Business.id) pk>",
                    "    <integer_column_info(Business.employees)>",
                    "    <string_column_info(Business.name)>",
                    "    <composite_info(Address, Business.location)>",
                    "        <enum_column_info(Address.state)>",
                    "        <string_column_info(Address.street)>",
                    "        <string_column_info(Address.zip)>",
                    "    <composite_info(Address, Business.other_location)>",
                    "        <enum_column_info(Address.state)>",
                    "        <string_column_info(Address.street)>",
                    "        <string_column_info(Address.zip)>",
                ]
            ),
        )
Beispiel #6
0
    def test_primary_keys_from_instance(self):
        info = meta.model_info(Owner)
        instance = Owner(id=1)

        self.assertIsNone(info.primary_keys_from_instance(None))

        key = info.primary_keys_from_instance(instance)
        self.assertEqual(key, 1)

        info = meta.model_info(CompositePkModel)
        instance = CompositePkModel(id=1, pk=2)

        key = info.primary_keys_from_instance(instance)
        self.assertDictEqual(key, {"id": 1, "pk": 2})
    def get_object(self):
        """Returns the object the view is displaying.

        We ignore the `lookup_field` and `lookup_url_kwarg` values only
        when tere are multiple primary keys
        """
        queryset = self.get_queryset()
        model = self.get_model()
        info = model_info(model)
        kwargs = self.kwargs.copy()

        # we want to honor DRF lookup_field and lookup_url_kwarg API
        # but only if they are defined and there is single primary key.
        # When there are multiple, all bets are off so we restrict url kwargs
        # to model column names
        if len(info.primary_keys) == 1:
            lookup_field = self.lookup_field
            lookup_url_kwarg = self.lookup_url_kwarg or lookup_field

            kwargs[lookup_field] = kwargs.pop(lookup_url_kwarg)

        obj = queryset.get(info.primary_keys_from_dict(kwargs))

        if not obj:
            raise Http404("No %s matches the given query." % model.__name__)

        return obj
Beispiel #8
0
    def build_nested_field(self, field_name, relation_info, nested_depth):
        """Builds nested serializer to handle relationshipped model."""
        target_model = relation_info.related_model
        nested_fields = self.get_nested_relationship_fields(relation_info, nested_depth)

        field_kwargs = self.get_relationship_kwargs(relation_info, nested_depth)
        field_kwargs = self.include_extra_kwargs(field_kwargs, self._extra_kwargs.get(field_name))
        nested_extra_kwargs = {}

        nested_info = meta.model_info(target_model)
        if not field_kwargs.get("required", True):
            for nested_field in nested_info.primary_keys:
                nested_extra_kwargs.setdefault(nested_field, {}).setdefault("required", False)

        if not field_kwargs.get("allow_nested_updates", True):
            nested_depth = 0
            for nested_field in nested_info.properties:
                nested_extra_kwargs.setdefault(nested_field, {}).setdefault("read_only", True)
                nested_extra_kwargs.setdefault(nested_field, {}).pop("required", None)

        class NestedSerializer(getattr(self.Meta, "nested_serializer_class", ModelSerializer)):
            class Meta:
                model = target_model
                session = self.session
                depth = max(0, nested_depth - 1)
                fields = nested_fields
                extra_kwargs = nested_extra_kwargs

        return type(str(target_model.__name__ + "Serializer"), (NestedSerializer,), {})(**field_kwargs)
Beispiel #9
0
    def get_fields(self):
        """Return the dict of field names -> field instances that should be
        used for `self.fields` when instantiating the serializer."""
        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__
        )

        declared_fields = copy.deepcopy(self._declared_fields)
        info = meta.model_info(self.model)
        depth = getattr(self.Meta, "depth", 0)

        if depth is not None:
            assert depth >= 0, "'depth' may not be negative."
            assert depth <= 5, "'depth' may not be greater than 5."

        field_names = self.get_field_names(declared_fields, info)

        # Determine the fields that should be included on the serializer.
        _fields = OrderedDict()

        for field_name in field_names:
            # If the field is explicitly declared on the class then use that.
            if field_name in declared_fields:
                _fields[field_name] = declared_fields[field_name]
                continue

            source = self._extra_kwargs.get(field_name, {}).get("source") or field_name

            _fields[field_name] = self.build_field(source, info, self.model, depth)

        return _fields
Beispiel #10
0
    def test_column_properties(self):
        info = meta.model_info(Owner)

        self.assertListEqual(
            list(info.column_properties),
            [("id", info.id), ("first_name", info.first_name), ("last_name", info.last_name)],
        )
Beispiel #11
0
    def to_internal_value(self, data):
        """Same as in DRF but also handle ``partial_by_pk`` by making all non-
        pk fields optional.

        Even though flag name implies it will make serializer partial,
        that is currently not possible in DRF as partial flag is checked
        on root serializer within serializer validation loops. As such,
        individual serializers cannot be marked partial. Therefore when
        flag is provided and primary key is provided in validated data,
        we physically mark all other fields as not required to
        effectively make them partial without using ``partial`` flag
        itself. To make serializer behave more or less like real partial
        serializer, only passed keys in input data are preserved in
        validated data. If they are not stripped, it is possible to
        remove some existing data.
        """
        if not self.partial_by_pk or not self.get_primary_keys(data):
            return super().to_internal_value(data)

        info = meta.model_info(self.model)

        for _, field in self.fields.items():
            if field.source not in info.primary_keys:
                field.required = False

        passed_keys = set(data)
        data = super().to_internal_value(data)

        for k in set(data) - passed_keys:
            if k in self.fields and self.fields[k].get_default() == data[k]:
                data.pop(k)

        return data
    def get_lookup_regex(self, viewset, lookup_prefix=""):
        """
        Given a viewset, return the portion of the url regex that is used to match against a single instance.

        Can be overwritten by providing a `lookup_url_regex` on the viewset.
        """

        lookup_url_regex = getattr(viewset, "lookup_url_regex", None)
        if lookup_url_regex:
            return lookup_url_regex

        model = getattr(viewset, "get_model", lambda: None)()
        if model:
            info = meta.model_info(model)
            base_regex = "(?P<{lookup_prefix}{lookup_url_kwarg}>{lookup_value})"

            lookup_keys = [getattr(viewset, "lookup_url_kwarg", None) or getattr(viewset, "lookup_field", None)]
            if not lookup_keys[0] or len(info.primary_keys) > 1:
                lookup_keys = list(info.primary_keys)

            regexes = []
            for key in lookup_keys:
                regexes.append(
                    base_regex.format(lookup_prefix=lookup_prefix, lookup_url_kwarg=key, lookup_value="[^/.]+")
                )

            return "/".join(regexes)

        return super().get_lookup_regex(viewset, lookup_prefix)
Beispiel #13
0
    def test_get_key(self):
        info = meta.model_info(Owner)
        owner = Owner(id=1)

        key = info.get_key(owner)
        self.assertEqual(key, (1, ))
        self.assertIsNone(info.get_key(Owner()))
Beispiel #14
0
    def test_identity_key_from_instance(self):
        info = meta.model_info(Owner)
        owner = Owner(id=1)

        key = info.identity_key_from_instance(owner)
        self.assertEqual(key, meta.Identity(Owner, (1, )))
        self.assertIsNone(info.identity_key_from_instance(Owner()))
Beispiel #15
0
    def expand_queryset(self, queryset, values):
        to_expand = []

        for value in values:
            to_load = []
            components = value.split(LOOKUP_SEP)

            model = queryset._only_entity_zero().class_
            for c in components:
                props = meta.model_info(model).relationships
                try:
                    field = getattr(model, c)
                    model = props[
                        c].relationship._dependency_processor.mapper.class_
                except (KeyError, AttributeError):
                    to_load = []
                    break
                else:
                    to_load.append(field)

            if to_load:
                to_expand.append(to_load)

        if to_expand:
            queryset = queryset.options(*[
                six.moves.reduce(lambda a, b: a.joinedload(b), expand, orm)
                for expand in to_expand
            ])

        return queryset
Beispiel #16
0
    def test_get_field(self):
        info = meta.model_info(Owner)
        self.assertIs(info.get_field("first_name"),
                      info.properties.get("first_name"))

        with self.assertRaises(FieldDoesNotExist):
            info.get_field("zzzzzz")
Beispiel #17
0
    def test_factory_with_relation(self):
        info = meta.model_info(Owner)
        formset_class = inlineformset_factory(relation=Owner.vehicles,
                                              fields=ALL_FIELDS,
                                              session=db)

        self.assertEqual(formset_class.fk, info.relationships["vehicles"])
Beispiel #18
0
    def expand_queryset(self, queryset, values):
        to_expand = []

        for value in values:
            to_load = []
            components = value.split(LOOKUP_SEP)

            model = queryset._only_entity_zero().class_
            for c in components:
                props = meta.model_info(model).relationships
                try:
                    field = getattr(model, c)
                    prop = props[c]
                    model = prop.relationship._dependency_processor.mapper.class_
                except (KeyError, AttributeError):
                    to_load = []
                    break
                else:
                    to_load.append(ToLoadField(field, prop.direction))

            if to_load:
                to_expand.append(to_load)

        if to_expand:
            queryset = queryset.options(*[
                six.moves.reduce(
                    lambda a, b: (a.selectinload(b.field) if b.direction in {
                        orm.interfaces.ONETOMANY, orm.interfaces.MANYTOMANY
                    } else a.joinedload(b.field)),
                    expand,
                    orm,
                ) for expand in to_expand
            ])

        return queryset
Beispiel #19
0
    def test_composite_meta(self):

        info = meta.model_info(Vertex)
        self.assertEqual(set(info.composites.keys()), {"start", "end"})

        self.assertListEqual(
            repr(info).split("\n"),
            [
                "<model_info(Vertex)>",
                "    <integer_column_info(Vertex.pk) pk>",
                "    <composite_info(Point, Vertex.end)>",
                "        <integer_column_info(Point.x)>",
                "        <integer_column_info(Point.y)>",
                "    <composite_info(Point, Vertex.start)>",
                "        <integer_column_info(Point.x)>",
                "        <integer_column_info(Point.y)>",
            ],
        )

        start = info.composites["start"]
        self.assertEqual(set(start.properties.keys()), {"x", "y"})
        self.assertEqual(start.properties["x"].property, Vertex.x1.property)
        self.assertEqual(start.properties["y"].property, Vertex.y1.property)
        self.assertIs(start.attribute, Vertex.start)

        end = info.composites["end"]
        self.assertEqual(set(end.properties.keys()), {"x", "y"})
        self.assertEqual(end.properties["x"].property, Vertex.x2.property)
        self.assertEqual(end.properties["y"].property, Vertex.y2.property)
        self.assertIs(end.attribute, Vertex.end)

        self.assertEqual(set(start.field_names), {"x", "y"})
        self.assertEqual(start.model_class, Point)
Beispiel #20
0
    def get_primary_keys(self, validated_data):
        """Returns the primary key values from validated_data."""
        if not validated_data:
            return

        info = meta.model_info(self.queryset._only_entity_zero().mapper)
        return info.primary_keys_from_dict(
            {getattr(self.fields.get(k), "source", None) or k: v for k, v in validated_data.items()}
        )
Beispiel #21
0
    def test_composite_meta(self):

        info = meta.model_info(Vertex)
        self.assertEqual(set(info.composites.keys()), {"start", "end"})

        start = info.composites["start"]
        self.assertEqual(set(start.properties.keys()), {"x", "y"})
        self.assertEqual(start.properties["x"].property, Vertex.x1.property)

        self.assertEqual(set(start.field_names), {"x", "y"})
 def test_plain_sqla(self):
     info = meta.model_info(AllKindsOfFields)
     col = info.decimal
     self.assertDictEqual(
         {
             "help_text": None,
             "label": "Decimal",
             "required": False,
             "validators": []
         }, col.field_kwargs)
Beispiel #23
0
    def __init__(self, *args, **kwargs):
        composite_attr = kwargs.pop("composite", None) or getattr(getattr(self, "Meta", None), "composite", None)
        self._info = meta.model_info(composite_attr.prop.parent).composites[composite_attr.prop.key]

        super().__init__(*args, **kwargs)
        self.composite_class = self._info.prop.composite_class
        self.read_only = False
        self.required = False
        self.default = None
        self.allow_nested_updates = True
        self._extra_kwargs = {}
Beispiel #24
0
    def test_formfield(self):
        info = meta.model_info(Vehicle)

        with self.assertRaises(ImproperlyConfigured):
            info.owner.formfield()

        formfield = info.owner.formfield(session=Owner.query.session)
        self.assertIsInstance(formfield, fields.ModelChoiceField)

        formfield = info.parts.formfield(session=Part.query.session)
        self.assertIsInstance(formfield, fields.ModelMultipleChoiceField)
Beispiel #25
0
    def test_relationship_meta(self):
        info = meta.model_info(Owner)

        rel = info.relationships["vehicles"]

        self.assertEqual(rel.related_model, Vehicle)
        self.assertEqual(rel.name, "vehicles")
        self.assertEqual(rel.direction, sa.orm.relationships.ONETOMANY)
        self.assertEqual(list(rel.foreign_keys), Vehicle._owner_id.property.columns)
        self.assertTrue(rel.uselist)
        self.assertEqual(repr(rel), "<relation_info(Owner.vehicles)>")
Beispiel #26
0
    def test_get_relation_objects_for_validation(self):
        instance = Vehicle()
        info = meta.model_info(instance)

        self.assertDictEqual(
            instance._get_relation_objects_for_validation(),
            {
                "options": info.options,
                "owner": info.owner,
                "parts": info.parts
            },
        )
    def get_url(self, obj, view_name, request, format):
        info = meta.model_info(obj.__class__)

        # Unsaved objects will not yet have a valid URL.
        if not all(getattr(obj, i) for i in info.primary_keys):
            return None

        if len(info.primary_keys) == 1:
            kwargs = {self.lookup_url_kwarg: getattr(obj, self.lookup_field)}
        else:
            kwargs = {k: getattr(obj, k) for k in info.primary_keys}

        return self.reverse(view_name, kwargs=kwargs, request=request, format=format)
Beispiel #28
0
def get_url_kwargs(model):
    """Gets kwargs for the UriField."""
    info = meta.model_info(model)
    lookup_field = list(info.primary_keys.keys())[0]

    field_kwargs = {
        "read_only": True,
        "view_name": get_detail_view_name(model),
        "lookup_field": lookup_field,
        "lookup_url_kwarg": "pk",
    }

    return field_kwargs
 def test_column_info_enum(self):
     info = meta.model_info(Vehicle)
     col = info.type
     self.assertFalse(col.null)
     self.assertDictEqual(
         {
             "choices": VehicleType,
             "help_text": None,
             "label": "Type",
             "required": True,
             "validators": []
         },
         col.field_kwargs,
     )
     self.assertTrue(col.required)
 def test_choice_enum(self):
     info = meta.model_info(Vehicle)
     col = info.paint
     self.assertDictEqual(
         {
             "choices": [(x, x) for x in COLORS],
             "help_text": None,
             "label": "Paint",
             "required": False,
             "validators": [],
         },
         col.field_kwargs,
     )
     self.assertEqual(col.parent_model, Vehicle)
     self.assertEqual(repr(col), "<choice_column_info(Vehicle.paint)>")