Skip to content

BaseField class

edgy.core.db.fields.base.BaseField

BaseField(*, default=Undefined, **kwargs)

Bases: BaseFieldType, FieldInfo

The base field for Edgy data model fields. It provides some helpers additional to BaseFieldType and inherits from FieldInfo for pydantic integration.

Allows factories to overwrite methods.

PARAMETER DESCRIPTION
default

TYPE: Any DEFAULT: Undefined

**kwargs

TYPE: Any DEFAULT: {}

Source code in edgy/core/db/fields/base.py
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
def __init__(
    self,
    *,
    default: Any = Undefined,
    **kwargs: Any,
) -> None:
    if "__type__" in kwargs:
        kwargs["field_type"] = kwargs.pop("__type__")
    self.explicit_none = default is None

    super().__init__(**kwargs)

    # set remaining attributes
    for name, value in kwargs.items():
        setattr(self, name, value)

    # null is used for nullable columns and is_required is False
    # this is required for backward compatibility and pydantic_core uses null=True too
    # for opting out of nullable columns overwrite the get_column(s) method
    if (
        self.null or self.server_default is not None or self.autoincrement
    ) and default is Undefined:
        default = None
    if default is not Undefined:
        self.default = default

no_copy class-attribute instance-attribute

no_copy = False

read_only class-attribute instance-attribute

read_only = False

inject_default_on_partial_update class-attribute instance-attribute

inject_default_on_partial_update = False

inherit class-attribute instance-attribute

inherit = True

skip_absorption_check class-attribute instance-attribute

skip_absorption_check = False

skip_reflection_type_check class-attribute instance-attribute

skip_reflection_type_check = False

field_type class-attribute instance-attribute

field_type = Any

factory class-attribute instance-attribute

factory = None

__original_type__ class-attribute instance-attribute

__original_type__ = None

name class-attribute instance-attribute

name = ''

secret class-attribute instance-attribute

secret = False

exclude class-attribute instance-attribute

exclude = False

server_default class-attribute instance-attribute

server_default = None

primary_key class-attribute instance-attribute

primary_key = False

autoincrement class-attribute instance-attribute

autoincrement = False

null class-attribute instance-attribute

null = False

index class-attribute instance-attribute

index = False

unique class-attribute instance-attribute

unique = False

registry property

registry

owner instance-attribute

owner

operator_mapping class-attribute instance-attribute

operator_mapping = {'is': 'is_', 'in': 'in_', 'exact': '__eq__', 'not': '__ne__', 'gt': '__gt__', 'ge': '__ge__', 'gte': '__ge__', 'lt': '__lt__', 'lte': '__le__', 'le': '__le__'}

explicit_none instance-attribute

explicit_none = default is None

default instance-attribute

default = default

clean

clean(field_name, value, for_query=False)

Validates a value and transform it into columns which can be used for querying and saving.

PARAMETER DESCRIPTION
field_name

TYPE: str

value

TYPE: Any

for_query

TYPE: bool DEFAULT: False

PARAMETER DESCRIPTION
field_name

the field name (can be different from name)

TYPE: str

value

the field value

TYPE: Any

Kwargs: for_query: Is used for querying. Should have all columns used for querying set. The columns used can differ especially for multi column fields.

Source code in edgy/core/db/fields/types.py
104
105
106
107
108
109
110
111
112
113
114
115
def clean(self, field_name: str, value: Any, for_query: bool = False) -> dict[str, Any]:
    """
    Validates a value and transform it into columns which can be used for querying and saving.

    Args:
        field_name: the field name (can be different from name)
        value: the field value
    Kwargs:
        for_query: Is used for querying. Should have all columns used for querying set.
                   The columns used can differ especially for multi column fields.
    """
    return {}

to_model

to_model(field_name, value)

Inverse of clean. Transforms column(s) to a field for edgy.Model. Validation happens later.

PARAMETER DESCRIPTION
field_name

TYPE: str

value

TYPE: Any

PARAMETER DESCRIPTION
field_name

the field name (can be different from name)

TYPE: str

value

the field value

TYPE: Any

Source code in edgy/core/db/fields/types.py
117
118
119
120
121
122
123
124
125
126
127
128
129
130
def to_model(
    self,
    field_name: str,
    value: Any,
) -> dict[str, Any]:
    """
    Inverse of clean. Transforms column(s) to a field for edgy.Model.
    Validation happens later.

    Args:
        field_name: the field name (can be different from name)
        value: the field value
    """
    return {field_name: value}

get_global_constraints

get_global_constraints(name, columns, schemes=())

Return global constraints and indexes. Useful for multicolumn fields

PARAMETER DESCRIPTION
name

TYPE: str

columns

TYPE: Sequence[Column]

schemes

TYPE: Sequence[str] DEFAULT: ()

Source code in edgy/core/db/fields/types.py
132
133
134
135
136
137
138
def get_global_constraints(
    self, name: str, columns: Sequence[sqlalchemy.Column], schemes: Sequence[str] = ()
) -> Sequence[Union[sqlalchemy.Constraint, sqlalchemy.Index]]:
    """Return global constraints and indexes.
    Useful for multicolumn fields
    """
    return []

get_embedded_fields

get_embedded_fields(field_name, fields)

Define extra fields on the fly. Often no owner is available yet.

PARAMETER DESCRIPTION
field_name

TYPE: str

fields

TYPE: dict[str, BaseFieldType]

PARAMETER DESCRIPTION
field_name

the field name (can be different from name)

TYPE: str

fields

the existing fields

TYPE: dict[str, BaseFieldType]

the returned fields are changed after return, so you should

return new fields or copies. Also set the owner of the field to them before returning

Source code in edgy/core/db/fields/types.py
140
141
142
143
144
145
146
147
148
149
150
151
152
153
def get_embedded_fields(
    self, field_name: str, fields: dict[str, BaseFieldType]
) -> dict[str, BaseFieldType]:
    """
    Define extra fields on the fly. Often no owner is available yet.

    Args:
        field_name: the field name (can be different from name)
        fields: the existing fields

    Note: the returned fields are changed after return, so you should
          return new fields or copies. Also set the owner of the field to them before returning
    """
    return {}

get_column_names

get_column_names(name='')
PARAMETER DESCRIPTION
name

TYPE: str DEFAULT: ''

Source code in edgy/core/db/fields/types.py
196
197
198
199
def get_column_names(self, name: str = "") -> frozenset[str]:
    if name:
        return cast("MetaInfo", self.owner.meta).field_to_column_names[name]
    return cast("MetaInfo", self.owner.meta).field_to_column_names[self.name]

operator_to_clause

operator_to_clause(field_name, operator, table, value)

Base implementation, adaptable

PARAMETER DESCRIPTION
field_name

TYPE: str

operator

TYPE: str

table

TYPE: Table

value

TYPE: Any

Source code in edgy/core/db/fields/base.py
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
def operator_to_clause(
    self, field_name: str, operator: str, table: sqlalchemy.Table, value: Any
) -> Any:
    """Base implementation, adaptable"""
    # Map the operation code onto SQLAlchemy's ColumnElement
    # https://docs.sqlalchemy.org/en/latest/core/sqlelement.html#sqlalchemy.sql.expression.ColumnElement
    # MUST raise an KeyError on missing columns, this code is used for the generic case if no field is available
    column = table.columns[field_name]
    operator = self.operator_mapping.get(operator, operator)
    if operator == "iexact":
        ESCAPE_CHARACTERS = ["%", "_"]
        has_escaped_character = any(c for c in ESCAPE_CHARACTERS if c in value)
        if has_escaped_character:
            value = value.replace("\\", "\\\\")
            # enable escape modifier
            for char in ESCAPE_CHARACTERS:
                value = value.replace(char, f"\\{char}")
        clause = column.ilike(value, escape="\\" if has_escaped_character else None)
        return clause
    elif operator in {
        "contains",
        "icontains",
        "startswith",
        "endswith",
        "istartswith",
        "iendswith",
    }:
        return getattr(column, operator)(value, autoescape=True)
    return getattr(column, operator)(value)

is_required

is_required()

Check if the argument is required.

RETURNS DESCRIPTION
bool

True if the argument is required, False otherwise.

Source code in edgy/core/db/fields/base.py
119
120
121
122
123
124
125
126
127
128
129
130
131
def is_required(self) -> bool:
    """Check if the argument is required.

    Returns:
        `True` if the argument is required, `False` otherwise.
    """
    if self.primary_key and self.autoincrement:
        return False
    return not (
        self.null
        or self.server_default is not None
        or ((self.default is not None or self.explicit_none) and self.default is not Undefined)
    )

has_default

has_default()

Checks if the field has a default value set

Source code in edgy/core/db/fields/base.py
133
134
135
136
137
def has_default(self) -> bool:
    """Checks if the field has a default value set"""
    return bool(
        (self.default is not None or self.explicit_none) and self.default is not Undefined
    )

get_columns

get_columns(name)

Returns the columns of the field being declared.

PARAMETER DESCRIPTION
name

TYPE: str

Source code in edgy/core/db/fields/base.py
139
140
141
142
143
def get_columns(self, name: str) -> Sequence[sqlalchemy.Column]:
    """
    Returns the columns of the field being declared.
    """
    return []

embed_field

embed_field(prefix, new_fieldname, owner=None, parent=None)

Embed this field or return None to prevent embedding. Must return a copy with name and owner set when not returning None.

PARAMETER DESCRIPTION
prefix

TYPE: str

new_fieldname

TYPE: str

owner

TYPE: Optional[type[BaseModelType]] DEFAULT: None

parent

TYPE: Optional[BaseField] DEFAULT: None

Source code in edgy/core/db/fields/base.py
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
def embed_field(
    self,
    prefix: str,
    new_fieldname: str,
    owner: Optional[type["BaseModelType"]] = None,
    parent: Optional["BaseField"] = None,
) -> Optional["BaseField"]:
    """
    Embed this field or return None to prevent embedding.
    Must return a copy with name and owner set when not returning None.
    """
    field_copy = copy.copy(self)
    field_copy.name = new_fieldname
    field_copy.owner = owner
    return field_copy

get_default_value

get_default_value()
Source code in edgy/core/db/fields/base.py
161
162
163
164
165
166
def get_default_value(self) -> Any:
    # single default
    default = getattr(self, "default", None)
    if callable(default):
        return default()
    return default

get_default_values

get_default_values(field_name, cleaned_data)
PARAMETER DESCRIPTION
field_name

TYPE: str

cleaned_data

TYPE: dict[str, Any]

Source code in edgy/core/db/fields/base.py
168
169
170
171
172
173
174
175
def get_default_values(self, field_name: str, cleaned_data: dict[str, Any]) -> dict[str, Any]:
    # for multidefaults overwrite in subclasses get_default_values to
    # parse default values differently
    # NOTE: multi value fields should always check here if defaults were already applied
    # NOTE: when build meta fields without columns this should be empty
    if field_name in cleaned_data:
        return {}
    return {field_name: self.get_default_value()}