예제 #1
0
    def test_lazy_table_reference(self):
        # These are equivalent:
        references_list = [
            LazyTableReference(table_class_name="Manager", app_name="music"),
            LazyTableReference(
                table_class_name="Manager",
                module_path="tests.example_apps.music.tables",
            ),
        ]

        for references in references_list:
            serialised = serialise_params(params={"references": references})
            self.assertTrue(
                serialised.params["references"].__repr__() == "Manager")

            self.assertTrue(len(serialised.extra_imports) == 1)
            self.assertEqual(
                serialised.extra_imports[0].__str__(),
                "from piccolo.table import Table",
            )

            self.assertTrue(len(serialised.extra_definitions) == 1)
            self.assertEqual(
                serialised.extra_definitions[0].__str__(),
                ('class Manager(Table, tablename="manager"): '
                 "id = Serial(null=False, primary_key=True, unique=False, "
                 "index=False, index_method=IndexMethod.btree, "
                 "choices=None, db_column_name='id', secret=False)"),
            )
예제 #2
0
    def test_lazy_table_reference(self):
        # These are equivalent:
        references_list = [
            LazyTableReference(
                table_class_name="Manager", app_name="example_app"
            ),
            LazyTableReference(
                table_class_name="Manager",
                module_path="tests.example_app.tables",
            ),
        ]

        for references in references_list:
            serialised = serialise_params(params={"references": references})
            self.assertTrue(
                serialised.params["references"].__repr__() == "Manager"
            )

            self.assertTrue(len(serialised.extra_imports) == 1)
            self.assertEqual(
                serialised.extra_imports[0].__str__(),
                "from piccolo.table import Table",
            )

            self.assertTrue(len(serialised.extra_definitions) == 1)
            self.assertEqual(
                serialised.extra_definitions[0].__str__(),
                'class Manager(Table, tablename="manager"): pass',
            )
예제 #3
0
    def test_str(self):
        self.assertEqual(
            LazyTableReference(
                table_class_name="Manager", app_name="example_app",
            ).__str__(),
            "App example_app.Manager",
        )

        self.assertEqual(
            LazyTableReference(
                table_class_name="Manager",
                module_path="tests.example_app.tables",
            ).__str__(),
            "Module tests.example_app.tables.Manager",
        )
예제 #4
0
    def test_init(self):
        """
        A ``LazyTableReference`` must be passed either an ``app_name`` or
        ``module_path`` argument.
        """
        with self.assertRaises(ValueError):
            LazyTableReference(table_class_name="Manager")

        with self.assertRaises(ValueError):
            LazyTableReference(
                table_class_name="Manager",
                app_name="example_app",
                module_path="tests.example_app.tables",
            )

        # Shouldn't raise exceptions:
        LazyTableReference(
            table_class_name="Manager", app_name="example_app",
        )
        LazyTableReference(
            table_class_name="Manager", module_path="tests.example_app.tables",
        )
예제 #5
0
파일: table.py 프로젝트: kremrik/piccolo
    def __init_subclass__(
        cls,
        tablename: t.Optional[str] = None,
        db: t.Optional[Engine] = None,
        tags: t.List[str] = [],
        help_text: t.Optional[str] = None,
    ):
        """
        Automatically populate the _meta, which includes the tablename, and
        columns.

        :param tablename:
            Specify a custom tablename. By default the classname is converted
            to snakecase.
        :param db:
            Manually specify an engine to use for connecting to the database.
            Useful when writing simple scripts. If not set, the engine is
            imported from piccolo_conf.py using ``engine_finder``.
        :param tags:
            Used for filtering, for example by ``table_finder``.
        :param help_text:
            A user friendly description of what the table is used for. It isn't
            used in the database, but will be used by tools such a Piccolo
            Admin for tooltips.

        """
        tablename = tablename if tablename else _camel_to_snake(cls.__name__)

        if tablename in PROTECTED_TABLENAMES:
            raise ValueError(
                f"{tablename} is a protected name, please give your table a "
                "different name.")

        columns: t.List[Column] = []
        default_columns: t.List[Column] = []
        non_default_columns: t.List[Column] = []
        foreign_key_columns: t.List[ForeignKey] = []
        secret_columns: t.List[Secret] = []

        cls.id = PrimaryKey()

        attribute_names = itertools.chain(
            *[i.__dict__.keys() for i in reversed(cls.__mro__)])
        unique_attribute_names = list(dict.fromkeys(attribute_names))

        for attribute_name in unique_attribute_names:
            if attribute_name.startswith("_"):
                continue

            attribute = getattr(cls, attribute_name)
            if isinstance(attribute, Column):
                # We have to copy, then override the existing column
                # definition, in case this column is inheritted from a mixin.
                # Otherwise, when we set attributes on that column, it will
                # effect all other users of that mixin.
                column = attribute.copy()
                setattr(cls, attribute_name, column)

                if isinstance(column, PrimaryKey):
                    # We want it at the start.
                    columns = [column] + columns  # type: ignore
                    default_columns.append(column)
                else:
                    columns.append(column)
                    non_default_columns.append(column)

                column._meta._name = attribute_name
                column._meta._table = cls

                if isinstance(column, Secret):
                    secret_columns.append(column)

                if isinstance(column, ForeignKey):
                    foreign_key_columns.append(column)

        cls._meta = TableMeta(
            tablename=tablename,
            columns=columns,
            default_columns=default_columns,
            non_default_columns=non_default_columns,
            foreign_key_columns=foreign_key_columns,
            secret_columns=secret_columns,
            tags=tags,
            help_text=help_text,
            _db=db,
        )

        for foreign_key_column in foreign_key_columns:
            params = foreign_key_column._meta.params
            references = params["references"]

            if isinstance(references, str):
                if references == "self":
                    references = cls
                else:
                    if "." in references:
                        # Don't allow relative modules - this may change in
                        # the future.
                        if references.startswith("."):
                            raise ValueError("Relative imports aren't allowed")

                        module_path, table_class_name = references.rsplit(
                            ".", maxsplit=1)
                    else:
                        table_class_name = references
                        module_path = cls.__module__

                    references = LazyTableReference(
                        table_class_name=table_class_name,
                        module_path=module_path,
                    )

            is_lazy = isinstance(references, LazyTableReference)
            is_table_class = inspect.isclass(references) and issubclass(
                references, Table)

            if is_lazy or is_table_class:
                foreign_key_column._foreign_key_meta.references = references
            else:
                raise ValueError(
                    "Error - ``references`` must be a ``Table`` subclass, or "
                    "a ``LazyTableReference`` instance.")

            # Record the reverse relationship on the target table.
            if is_table_class:
                references._meta._foreign_key_references.append(
                    foreign_key_column)
            elif is_lazy:
                LAZY_COLUMN_REFERENCES.foreign_key_columns.append(
                    foreign_key_column)

            # Allow columns on the referenced table to be accessed via
            # auto completion.
            if is_table_class:
                foreign_key_column.set_proxy_columns()
예제 #6
0
class Genre(Table):
    name = Varchar()
    bands = M2M(LazyTableReference("GenreToBand", module_path=__name__))