Model

Bases: BaseModel

The base model representing SQLite tables Inherits directly from pydantic.BaseModel

Attributes:

Name Type Description
__rowid__ int | None

(class attribute) when an object is returned by a query it will contain the rowid field that can be used for update and deletion.

__pk__ str | None

(class attribute) Holds the primary key column name of the table

__tablename__ str

(class attribute) the name of the table in the database

__schema__(str) str

the (class attribute) schema for the table.

Example
from ardilla import Model, Field
# Field is actually pydantic.Field but it's imported here for the convenience of the developer

class User(Model):
    __tablename__ = 'users' # by default the tablename is just the model's name in lowercase
    id: int = Field(primary=True) # sets this field as the primary key
    name: str
Source code in ardilla/models.py
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
class Model(BaseModel):
    """
    The base model representing SQLite tables
    Inherits directly from pydantic.BaseModel

    Attributes:
        __rowid__ (int | None): (class attribute) when an object is returned by a query it will 
            contain the rowid field that can be used for update and deletion.
        __pk__ (str | None): (class attribute) Holds the primary key column name of the table
        __tablename__ (str): (class attribute) the name of the table in the database
        __schema__(str): the (class attribute) schema for the table.

    Example:
        ```py
        from ardilla import Model, Field
        # Field is actually pydantic.Field but it's imported here for the convenience of the developer

        class User(Model):
            __tablename__ = 'users' # by default the tablename is just the model's name in lowercase
            id: int = Field(primary=True) # sets this field as the primary key
            name: str
        ```
    """
    __rowid__: Optional[int] = PrivateAttr(default=None)
    __pk__: Optional[str]  # tells the model which key to idenfity as primary
    __tablename__: str  # will default to the lowercase name of the subclass
    __schema__: str  # best effort will be made if it's missing
    # there's no support for constrains or foreign fields yet but you can
    # define your own schema to support them

    def __init_subclass__(cls, **kws) -> None:

        for field in cls.__fields__.values():
            if field.type_ not in FIELD_MAPPING:
                raise ModelIntegrityError(
                    f'Field "{field.name}" of model "{cls.__name__}" is of unsupported type "{field.type_}"'
                )

            if field.field_info.extra.keys() & {'primary', 'primary_key', 'pk'}:
                if getattr(cls, '__pk__', None) not in {None, field.name}:
                    raise ModelIntegrityError('More than one fields defined as primary')

                cls.__pk__ = field.name 

        if not hasattr(cls, "__schema__"):
            cls.__schema__ = make_table_schema(cls)

        if not hasattr(cls, '__pk__'):
            cls.__pk__ = get_pk(cls.__schema__)

        if not hasattr(cls, "__tablename__"):
            tablename = get_tablename(cls)
            setattr(cls, "__tablename__", tablename)

        super().__init_subclass__(**kws)

    def __str__(self) -> str:
        return f"{self!r}"

Fields

Helper class to generate foreing key field constrains.

Intead of instantiating this class the developer should use the already instantiated ardilla.fields.ForeignKey instead of directly instantiating this class.

Attributes:

Name Type Description
NO_ACTION str

(class attribute) The database won't take action. This most likely will result in errors

RESTRICT str

(class attribute) The app will not be able to delete the foreing row unless there's no related child elements left

SET_NULL str

(class attribute) The app will set the child to Null if the parent is deleted

SET_DEFAULT str

(class attribute) Returns the value of this field to the default of the child when the parent is deleted or updated

CASCADE str

(class attribute) If the parent gets deleted or updated the child follows

Source code in ardilla/fields.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
class _ForeignFieldMaker():
    """
    Helper class to generate foreing key field constrains.

    Intead of instantiating this class the developer should use 
    the already instantiated `ardilla.fields.ForeignKey`
    instead of directly instantiating this class.

    Attributes:
        NO_ACTION (str): (class attribute) The database won't take action. This most likely will result in errors
        RESTRICT (str): (class attribute) The app will not be able to delete the foreing row unless there's no related child elements left
        SET_NULL (str): (class attribute) The app will set the child to Null if the parent is deleted
        SET_DEFAULT (str): (class attribute) Returns the value of this field to the default of the child when the parent is deleted or updated
        CASCADE (str): (class attribute) If the parent gets deleted or updated the child follows  

    """
    NO_ACTION = 'NO ACTION'
    RESTRICT = 'RESTRICT'
    SET_NULL = 'SET NULL'
    SET_DEFAULT = 'SET DEFAULT'
    CASCADE = 'CASCADE'

    def __call__(
        self,
        *,
        references: type[Model],
        on_delete: str = NO_ACTION, 
        on_update: str = NO_ACTION,
        **kws,
    ) -> Any:
        """
        Args:
            references (type[Model]):
                The model this foreign key points to
            on_delete (str): defaults to 'NO ACTION'
                what happens when the referenced row gets deleted
            on_update (str): defaults to 'NO ACTION'
                what happens when the referenced row gets updated
        Returns:
            A `pydantic.Field` with extra metadata for the schema creation
        Raises:
            KeyError: if the referenced value is not a type of model
            ValueError: if the referenced model does not have a primary key or has not yet been instantiated
        """
        if not issubclass(references, Model):
            raise TypeError('The referenced type must be a subclass of ardilla.Model')
        fk = getattr(references, '__pk__', None)
        tablename = getattr(references, '__tablename__')

        if not fk:
            raise ValueError('The referenced model requires to have a primary key')

        return Field(
            references=tablename, 
            fk=fk,
            on_delete=on_delete,
            on_update=on_update,
            **kws
        )

__call__(*, references, on_delete=NO_ACTION, on_update=NO_ACTION, **kws)

Parameters:

Name Type Description Default
references type[Model]

The model this foreign key points to

required
on_delete str

defaults to 'NO ACTION' what happens when the referenced row gets deleted

NO_ACTION
on_update str

defaults to 'NO ACTION' what happens when the referenced row gets updated

NO_ACTION

Returns:

Type Description
Any

A pydantic.Field with extra metadata for the schema creation

Raises:

Type Description
KeyError

if the referenced value is not a type of model

ValueError

if the referenced model does not have a primary key or has not yet been instantiated

Source code in ardilla/fields.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
def __call__(
    self,
    *,
    references: type[Model],
    on_delete: str = NO_ACTION, 
    on_update: str = NO_ACTION,
    **kws,
) -> Any:
    """
    Args:
        references (type[Model]):
            The model this foreign key points to
        on_delete (str): defaults to 'NO ACTION'
            what happens when the referenced row gets deleted
        on_update (str): defaults to 'NO ACTION'
            what happens when the referenced row gets updated
    Returns:
        A `pydantic.Field` with extra metadata for the schema creation
    Raises:
        KeyError: if the referenced value is not a type of model
        ValueError: if the referenced model does not have a primary key or has not yet been instantiated
    """
    if not issubclass(references, Model):
        raise TypeError('The referenced type must be a subclass of ardilla.Model')
    fk = getattr(references, '__pk__', None)
    tablename = getattr(references, '__tablename__')

    if not fk:
        raise ValueError('The referenced model requires to have a primary key')

    return Field(
        references=tablename, 
        fk=fk,
        on_delete=on_delete,
        on_update=on_update,
        **kws
    )