baserow.field

The module contains definitions for the values of table fields that do not directly translate into built-in types.

  1"""
  2The module contains definitions for the values of table fields that do not
  3directly translate into built-in types.
  4"""
  5
  6from __future__ import annotations
  7import abc
  8import datetime
  9import enum
 10from io import BufferedReader
 11from pathlib import Path
 12from typing import TYPE_CHECKING, Generic, Optional, TypeVar, Union
 13
 14from pydantic import BaseModel, ConfigDict, Field, RootModel, model_serializer, model_validator
 15
 16from baserow.client import GlobalClient
 17from baserow.color import ColorSequence
 18from baserow.error import PydanticGenericMetadataError
 19from baserow.field_config import CreatedByFieldConfig, CreatedOnFieldConfig, FieldConfigType, FileFieldConfig, LastModifiedByFieldConfig, LastModifiedFieldConfig, MultipleCollaboratorsFieldConfig, MultipleSelectFieldConfig, SelectEntryConfig, SingleSelectFieldConfig
 20from baserow.file import File
 21
 22if TYPE_CHECKING:
 23    from baserow.client import Client
 24
 25
 26class FieldType(str, enum.Enum):
 27    """The various types that Baserow fields can have."""
 28    TEXT = "text"
 29    NUMBER = "number"
 30    LONG_TEXT = "long_text"
 31    LINK_ROW = "link_row"
 32    BOOLEAN = "boolean"
 33    DATE = "date"
 34    RATING = "rating"
 35    LAST_MODIFIED = "last_modified"
 36    LAST_MODIFIED_BY = "last_modified_by"
 37    CREATED_ON = "created_on"
 38    CREATED_BY = "created_by"
 39    DURATION = "duration"
 40    URL = "url"
 41    EMAIL = "email"
 42    FILE = "file"
 43    SINGLE_SELECT = "single_select"
 44    MULTIPLE_SELECT = "multiple_select"
 45    PHONE_NUMBER = "phone_number"
 46    FORMULA = "formula"
 47    ROLLUP = "rollup"
 48    LOOKUP = "lookup"
 49    MULTIPLE_COLLABORATORS = "multiple_collaborators"
 50    UUID = "uuid"
 51    AUTONUMBER = "autonumber"
 52    PASSWORD = "password"
 53
 54
 55class BaserowField(BaseModel, abc.ABC):
 56    """
 57    Abstract base class for all Baserow fields that are not covered by the
 58    built-in types.
 59
 60    This class also handles tracking changes, which are initially local and only
 61    applied to Baserow when Table.update() is called. For example, the method
 62    TableLinkField.append() adds a new link to a record, but this change is only
 63    written to Baserow when Table.update() is invoked. Such actions can be
 64    registered with BaserowField.register_pending_change(). If an object with
 65    pending changes is deleted (__del__), a corresponding warning is issued.
 66    """
 67
 68    @classmethod
 69    @abc.abstractmethod
 70    def default_config(cls) -> FieldConfigType:
 71        """Returns the default field config for a given field type."""
 72
 73    @classmethod
 74    @abc.abstractmethod
 75    def read_only(cls) -> bool:
 76        """
 77        Read only fields (like modification date or UUID fields) will be ignored
 78        during update calls like `Table.update()`.
 79        """
 80
 81    _pending_changes: list[str] = []
 82    """See documentation of `BaserowField.register_pending_changes()`."""
 83
 84    def register_pending_change(self, description: str):
 85        """
 86        Registers a change to the field, which is currently only stored locally
 87        and must be explicitly applied to Baserow using `Table.update()`.
 88
 89        Args:
 90            description (str): A description of the change in data.
 91        """
 92        self._pending_changes.append(description)
 93
 94    def changes_applied(self):
 95        """
 96        Is called by `Table.update()` after all pending changes have been
 97        written to Baserow.
 98        """
 99        self._pending_changes = []
100
101    def __del__(self):
102        if len(self._pending_changes) != 0:
103            changes = ["- " + change for change in self._pending_changes]
104            print(f"WARNING: THERE ARE STILL PENDING CHANGES IN FIELD {self.__class__.__name__}")  # noqa: F821
105            print("\n".join(changes))
106            print(
107                "It looks like `Table.update()` was not called to apply these changes to Baserow.",
108            )
109
110
111class User(BaseModel):
112    """
113    A table field that contains one Baserow system user.
114    """
115    user_id: Optional[int] = Field(alias=str("id"))
116    name: Optional[str] = Field(alias=str("name"))
117
118
119class CreatedByField(User, BaserowField):
120    """
121    Field tracking the user who created an entry.
122    """
123    @classmethod
124    def default_config(cls) -> FieldConfigType:
125        return CreatedByFieldConfig()
126
127    @classmethod
128    def read_only(cls) -> bool:
129        return True
130
131
132class LastModifiedByField(User, BaserowField):
133    """
134    Field tracking the user who last modified a record.
135    """
136    @classmethod
137    def default_config(cls) -> FieldConfigType:
138        return LastModifiedByFieldConfig()
139
140    @classmethod
141    def read_only(cls) -> bool:
142        return True
143
144
145class CreatedOnField(BaserowField, RootModel[datetime.datetime]):
146    """
147    Field containing the creation timestamp of a row.
148    """
149    root: datetime.datetime
150
151    @classmethod
152    def default_config(cls) -> FieldConfigType:
153        return CreatedOnFieldConfig()
154
155    @classmethod
156    def read_only(cls) -> bool:
157        return True
158
159
160class LastModifiedOnField(BaserowField, RootModel[datetime.datetime]):
161    """
162    Field containing the last modification timestamp of a row.
163    """
164    root: datetime.datetime
165
166    @classmethod
167    def default_config(cls) -> FieldConfigType:
168        return LastModifiedFieldConfig()
169
170    @classmethod
171    def read_only(cls) -> bool:
172        return True
173
174
175class MultipleCollaboratorsField(BaserowField, RootModel[list[User]]):
176    """
177    A table field that contains one or multiple Baserow system user(s).
178    """
179    root: list[User]
180
181    @classmethod
182    def default_config(cls) -> FieldConfigType:
183        return MultipleCollaboratorsFieldConfig()
184
185    @classmethod
186    def read_only(cls) -> bool:
187        return False
188
189
190class FileField(BaserowField, RootModel[list[File]]):
191    """
192    A file field allows you to easily upload one or more files from your device
193    or from a URL.
194    """
195    root: list[File]
196
197    @classmethod
198    def default_config(cls) -> FieldConfigType:
199        return FileFieldConfig()
200
201    @classmethod
202    def read_only(cls) -> bool:
203        return False
204
205    @classmethod
206    async def from_file(
207        cls,
208        file: BufferedReader | str | Path,
209        name: Optional[str] = None,
210        client: Optional[Client] = None,
211    ):
212        """
213        This method takes a local file (either as a `BufferedReader` or as a
214        path) and uploads it to Baserow's media storage, handling the linkage
215        between the field and the stored file. A `FileField` instance containing
216        the uploaded file is returned. Calling this method initiates the file
217        upload, which may take some time depending on the file size.
218
219        Note that this method does not use the client associated with the table.
220
221        ```python
222        # By path.
223        await Book(
224            cover=await FileField.from_file("path/to/image.png"),
225        ).create()
226
227        # With BufferedReader.
228        await Book(
229            cover=await FileField.from_file(open("path/to/image.png", "rb")),
230        ).create()
231        ```
232
233        Args:
234            file (BufferedReader | str | Path): File to be uploaded.
235            name (str | None): Optional human-readable name of the file, as it
236                should be displayed in the Baserow frontend.
237            client (Client | None): Specifies which API client should be used.
238                If none is provided, the `GlobalClient` will be used. Note that
239                this method does not automatically use the client associated
240                with the table.
241        """
242        rsl = cls(root=[])
243        await rsl.append_file(file, name, client, register_pending_change=False)
244        return rsl
245
246    @classmethod
247    async def from_url(
248        cls,
249        url: str,
250        name: Optional[str] = None,
251        client: Optional[Client] = None,
252    ):
253        """
254        This method takes the URL of a publicly accessible file on the internet
255        and uploads it to Baserow's media storage, managing the linkage between
256        the field and the stored file. Calling this method initiates the file
257        upload, which may take some time depending on the file size.
258
259        Note that this method does not use the client associated with the table.
260
261        ```python
262        await Book(
263            cover=await FileField.from_url("https://example.com/image.png"),
264        ).create()
265        ```
266
267        Args:
268            url (str): URL of the file to be uploaded.
269            name (str | None): Optional human-readable name of the file, as it
270                should be displayed in the Baserow frontend.
271            client (Client | None): Specifies which API client should be used.
272                If none is provided, the `GlobalClient` will be used. Note that
273                this method does not automatically use the client associated
274                with the table.
275        """
276        rsl = cls(root=[])
277        await rsl.append_file_from_url(url, name, client, register_pending_change=False)
278        return rsl
279
280    async def append_file(
281        self,
282        file: BufferedReader | str | Path,
283        name: Optional[str] = None,
284        client: Optional[Client] = None,
285        register_pending_change: bool = True,
286    ):
287        """
288        This method takes a local file (either as a `BufferedReader` or as a
289        path) and uploads it to Baserow's media storage and adds it to the file
290        field.Calling this method initiates the file upload, which may take some
291        time depending on the file size.
292
293        Further information about uploading and setting files can be found in
294        the documentation of `client.upload_file()`. After this method
295        `Table.update()` must be called manually to apply the changes.
296
297        ```python
298        book = Book.by_id(ROW_ID)
299
300        # By path.
301        await book.cover.append_file("path/to/image.png")
302
303        # With BufferedReader.
304        await book.cover.append_file(open("path/to/image.png", "rb"))
305
306        book.update()
307        ```
308
309        Args:
310            file (BufferedReader | str | Path): File to be uploaded.
311            name (str | None): Optional human-readable name of the file, as it
312                should be displayed in the Baserow frontend.
313            client (Client | None): Specifies which API client should be used.
314                If none is provided, the `GlobalClient` will be used. Note that
315                this method does not automatically use the client associated
316                with the table.
317            register_pending_change (bool): Internal option for the
318                `FileField.from_file()` and `FileField.from_url()` methods. When
319                set to false, tracking of pending changes for this call is
320                disabled. This is only useful in situations where
321                `Table.update()` will be called anyway, such as when the method
322                is invoked within the initialization of a model.
323        """
324        if not isinstance(file, BufferedReader):
325            file = open(file, "rb")
326        if client is None:
327            client = GlobalClient()
328        new_file = await client.upload_file(file)
329        if name is not None:
330            new_file.original_name = name
331        self.root.append(new_file)
332        if register_pending_change:
333            self.register_pending_change(
334                f"file '{new_file.original_name}' added",
335            )
336
337    async def append_file_from_url(
338        self,
339        url: str,
340        name: Optional[str] = None,
341        client: Optional[Client] = None,
342        register_pending_change: bool = True,
343    ):
344        """
345        This method takes the URL of a publicly accessible file on the internet
346        and uploads it to Baserow's media storage and adds it to the file
347        field.Calling this method initiates the file upload, which may take some
348        time depending on the file size.
349
350        Further information about uploading and setting files can be found in
351        the documentation of `client.upload_file()`. After this method
352        `Table.update()` must be called manually to apply the changes.
353
354        ```python
355        book = Book.by_id(ROW_ID)
356        await book.cover.append_file_from_url("https://example.com/image.png")
357        book.update()
358        ```
359
360        Args:
361            url (str): The URL of the file.
362            name (str | None): Optional human-readable name of the file, as it
363                should be displayed in the Baserow frontend.
364            client (Client | None): Specifies which API client should be used.
365                If none is provided, the `GlobalClient` will be used. Note that
366                this method does not automatically use the client associated
367                with the table.
368            register_pending_change (bool): Internal option for the
369                `FileField.from_file()` and `FileField.from_url()` methods. When
370                set to false, tracking of pending changes for this call is
371                disabled. This is only useful in situations where
372                `Table.update()` will be called anyway, such as when the method
373                is invoked within the initialization of a model.
374        """
375        if client is None:
376            client = GlobalClient()
377        new_file = await client.upload_file_via_url(url)
378        if name is not None:
379            new_file.original_name = name
380        self.root.append(new_file)
381        if register_pending_change:
382            self.register_pending_change(f"file from url '{url}' added")
383
384    def clear(self):
385        """
386        Removes all files from field. After that, `Table.update()` must be called
387        to apply the changes.
388
389        ```python
390        book = Book.by_id(ROW_ID)
391        await book.cover.clear()
392        book.update()
393        ```
394        """
395        self.root.clear()
396        self.register_pending_change("remove all files in field")
397
398
399SelectEnum = TypeVar("SelectEnum", bound=enum.Enum)
400"""
401Instances of a SelectEntry have to be bound to a enum which contain the possible
402values of the select entry.
403"""
404
405
406class SelectEntry(BaseModel, Generic[SelectEnum]):
407    """A entry in a single or multiple select field."""
408    entry_id: Optional[int] = Field(default=None, alias="id")
409    value: Optional[SelectEnum] = None
410    color: Optional[str] = None
411
412    model_config = ConfigDict(populate_by_name=True)
413
414    @model_validator(mode="after")
415    def id_or_value_must_be_set(self: "SelectEntry") -> "SelectEntry":
416        if self.entry_id is None and self.value is None:
417            raise ValueError(
418                "At least one of the entry_id and value fields must be set"
419            )
420        return self
421
422    @model_serializer
423    def serialize(self) -> Union[int, str]:
424        """
425        Serializes the field into the data structure required by the Baserow
426        API. If an entry has both an id and a value set, the id is used.
427        Otherwise the set field is used.
428
429        From the Baserow API documentation: Accepts an integer or a text value
430        representing the chosen select option id or option value. A null value
431        means none is selected. In case of a text value, the first matching
432        option is selected. 
433        """
434        if self.entry_id is not None:
435            return self.entry_id
436        if self.value is not None:
437            return self.value.value
438        raise ValueError("both fields id and value are unset for this entry")
439
440    @classmethod
441    def _get_all_possible_values(cls) -> list[str]:
442        metadata = cls.__pydantic_generic_metadata__
443        if "args" not in metadata:
444            raise PydanticGenericMetadataError.args_missing(
445                cls.__class__.__name__,
446                "select entry enum",
447            )
448        if len(metadata["args"]) < 1:
449            raise PydanticGenericMetadataError.args_empty(
450                cls.__class__.__name__,
451                "select entry enum",
452            )
453        select_enum = metadata["args"][0]
454        return [item.value for item in select_enum]
455
456    @classmethod
457    def _options_config(cls) -> list[SelectEntryConfig]:
458        rsl: list[SelectEntryConfig] = []
459        color_sequence = ColorSequence()
460        i = 0
461        for value in cls._get_all_possible_values():
462            rsl.append(SelectEntryConfig(
463                id=i,
464                value=value,
465                color=color_sequence.get_color(),
466            ))
467            i += 1
468        return rsl
469
470
471class SingleSelectField(SelectEntry[SelectEnum], BaserowField):
472    """Single select field in a table."""
473    @classmethod
474    def default_config(cls) -> FieldConfigType:
475        options = super(SingleSelectField, cls)._options_config()
476        return SingleSelectFieldConfig(select_options=options)
477
478    @classmethod
479    def read_only(cls) -> bool:
480        return False
481
482    @classmethod
483    def from_enum(cls, select_enum: SelectEnum):
484        """
485        This function can be used to directly obtain the correct instance of the
486        field abstraction from an enum. Primarily, this function is a quality of
487        life feature for directly setting a field value in a model
488        initialization. This replaces the somewhat unergonomic and unintuitive
489        syntax which would be used otherwise.
490
491        ```python
492        class Genre(str, enum.Enum):
493            FICTION = "Fiction"
494            EDUCATION = "Education"
495
496        class Book(Table):
497            [...]
498            genre: Optional[SingleSelectField[Genre]] = Field(default=None)
499
500        # Can use this...
501        await Book(
502            genre=SingleSelectField.from_enum(Genre.FICTION),
503        ).create()
504
505        # ...instead of
506        await Book(
507            genre=SingleSelectField[Genre](value=Genre.FICTION)
508        ).create()
509        ```
510
511        Args:
512            select_enum (SelectEnum): Enum to which the field should be set.add 
513        """
514        return SingleSelectField[type(select_enum)](value=select_enum)
515
516    def set(self, instance: SelectEnum):
517        """
518        Set the value of the field. Please note that this method does not update
519        the record on Baserow. You have to call `Table.update()` afterwards.
520
521        Args:
522            instance (SelectEnum): The enum which should be set in this field.
523        """
524        self.entry_id = None
525        self.value = instance
526        self.color = None
527        self.register_pending_change(f"set SingleSelect to '{instance.value}'")
528
529
530class MultipleSelectField(BaserowField, RootModel[list[SelectEntry]], Generic[SelectEnum]):
531    """Multiple select field in a table."""
532    root: list[SelectEntry[SelectEnum]]
533
534    @classmethod
535    def read_only(cls) -> bool:
536        return False
537
538    @classmethod
539    def from_enums(cls, *select_enums: SelectEnum):
540        """
541        This function can be used to directly obtain the correct instance of the
542        field abstraction from one or multiple enum(s). Primarily, this function
543        is a quality of life feature for directly setting a field value in a
544        model initialization. This replaces the somewhat unergonomic and
545        unintuitive syntax which would be used otherwise.
546
547        ```python
548        class Keyword(str, enum.Enum):
549            ADVENTURE = "Adventure"
550            FICTION = "Fiction"
551            TECH = "Text"
552
553        class Book(Table):
554            [...]
555            keywords: Optional[MultipleSelectField[Keyword]] = Field(default=None)
556
557        await Book(
558            keywords=MultipleSelectField.from_enums(Keyword.ADVENTURE, Keyword.FICTION)
559        ).create()
560        ```
561
562        Args:
563            *select_enum (SelectEnum | list[SelectEnum]): Enum(s) value(s) to be part
564                of the select field.
565        """
566        if not select_enums:
567            raise ValueError("At least one enum must be provided")
568        select_enum_type = type(select_enums[0])
569        enums: list[SelectEntry[SelectEnum]] = []
570        for enum in select_enums:
571            enums.append(SelectEntry[type(enum)](value=enum))
572        return MultipleSelectField[select_enum_type](root=enums)
573
574    def append(self, *select_enums: SelectEnum):
575        """
576        Append one or multiple enum(s) to the field. Please note that this
577        method does not update the record on Baserow. You have to call
578        `Table.update()` afterwards.
579
580        Args:
581            *select_enum (SelectEnum | list[SelectEnum]): Enum(s) value(s) to be
582                added the the select field.
583        """
584        names: list[str] = []
585        for enum in select_enums:
586            self.root.append(SelectEntry(value=enum))
587            names.append(enum.name)
588        self.register_pending_change(
589            f"append enum(s) {', '.join(names)} to multiple select field",
590        )
591
592    def clear(self):
593        """
594        Remove all enums currently set for this field. Please note that this
595        method does not update the record on Baserow. You have to call
596        `Table.update()` afterwards.
597        """
598        self.root.clear()
599        self.register_pending_change(
600            f"removed all enum(s) from multiple select field",
601        )
602
603    def remove(self, *select_enums: SelectEnum):
604        """
605        Remove one or multiple enum(s) from the field. Please note that this
606        method does not update the record on Baserow. You have to call
607        `Table.update()` afterwards.
608
609        Args:
610            *select_enum (SelectEnum | list[SelectEnum]): Enum(s) value(s) to be
611                removed the the select field.
612        """
613        to_be_removed = [
614            entry for entry in self.root if entry. value in select_enums]
615        self.root = [
616            entry for entry in self.root if entry not in to_be_removed
617        ]
618        names = [
619            entry.value.name for entry in to_be_removed if entry.value is not None]
620        self.register_pending_change(
621            f"removed enum(s) {', '.join(names)} from multiple select field",
622        )
623
624    @classmethod
625    def default_config(cls) -> FieldConfigType:
626        metadata = cls.__pydantic_generic_metadata__
627        if "args" not in metadata:
628            raise PydanticGenericMetadataError.args_missing(
629                cls.__class__.__name__,
630                "select entry enum",
631            )
632        if len(metadata["args"]) < 1:
633            raise PydanticGenericMetadataError.args_empty(
634                cls.__class__.__name__,
635                "select entry enum",
636            )
637        select_enum = metadata["args"][0]
638        rsl: list[SelectEntryConfig] = []
639        color_sequence = ColorSequence()
640        i = 0
641        for item in select_enum:
642            rsl.append(SelectEntryConfig(
643                id=i,
644                value=item.value,
645                color=color_sequence.get_color(),
646            ))
647            i += 1
648        return MultipleSelectFieldConfig(select_options=rsl)
class FieldType(builtins.str, enum.Enum):
27class FieldType(str, enum.Enum):
28    """The various types that Baserow fields can have."""
29    TEXT = "text"
30    NUMBER = "number"
31    LONG_TEXT = "long_text"
32    LINK_ROW = "link_row"
33    BOOLEAN = "boolean"
34    DATE = "date"
35    RATING = "rating"
36    LAST_MODIFIED = "last_modified"
37    LAST_MODIFIED_BY = "last_modified_by"
38    CREATED_ON = "created_on"
39    CREATED_BY = "created_by"
40    DURATION = "duration"
41    URL = "url"
42    EMAIL = "email"
43    FILE = "file"
44    SINGLE_SELECT = "single_select"
45    MULTIPLE_SELECT = "multiple_select"
46    PHONE_NUMBER = "phone_number"
47    FORMULA = "formula"
48    ROLLUP = "rollup"
49    LOOKUP = "lookup"
50    MULTIPLE_COLLABORATORS = "multiple_collaborators"
51    UUID = "uuid"
52    AUTONUMBER = "autonumber"
53    PASSWORD = "password"

The various types that Baserow fields can have.

TEXT = <FieldType.TEXT: 'text'>
NUMBER = <FieldType.NUMBER: 'number'>
LONG_TEXT = <FieldType.LONG_TEXT: 'long_text'>
BOOLEAN = <FieldType.BOOLEAN: 'boolean'>
DATE = <FieldType.DATE: 'date'>
RATING = <FieldType.RATING: 'rating'>
LAST_MODIFIED = <FieldType.LAST_MODIFIED: 'last_modified'>
LAST_MODIFIED_BY = <FieldType.LAST_MODIFIED_BY: 'last_modified_by'>
CREATED_ON = <FieldType.CREATED_ON: 'created_on'>
CREATED_BY = <FieldType.CREATED_BY: 'created_by'>
DURATION = <FieldType.DURATION: 'duration'>
URL = <FieldType.URL: 'url'>
EMAIL = <FieldType.EMAIL: 'email'>
FILE = <FieldType.FILE: 'file'>
SINGLE_SELECT = <FieldType.SINGLE_SELECT: 'single_select'>
MULTIPLE_SELECT = <FieldType.MULTIPLE_SELECT: 'multiple_select'>
PHONE_NUMBER = <FieldType.PHONE_NUMBER: 'phone_number'>
FORMULA = <FieldType.FORMULA: 'formula'>
ROLLUP = <FieldType.ROLLUP: 'rollup'>
LOOKUP = <FieldType.LOOKUP: 'lookup'>
MULTIPLE_COLLABORATORS = <FieldType.MULTIPLE_COLLABORATORS: 'multiple_collaborators'>
UUID = <FieldType.UUID: 'uuid'>
AUTONUMBER = <FieldType.AUTONUMBER: 'autonumber'>
PASSWORD = <FieldType.PASSWORD: 'password'>
Inherited Members
enum.Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
class BaserowField(pydantic.main.BaseModel, abc.ABC):
 56class BaserowField(BaseModel, abc.ABC):
 57    """
 58    Abstract base class for all Baserow fields that are not covered by the
 59    built-in types.
 60
 61    This class also handles tracking changes, which are initially local and only
 62    applied to Baserow when Table.update() is called. For example, the method
 63    TableLinkField.append() adds a new link to a record, but this change is only
 64    written to Baserow when Table.update() is invoked. Such actions can be
 65    registered with BaserowField.register_pending_change(). If an object with
 66    pending changes is deleted (__del__), a corresponding warning is issued.
 67    """
 68
 69    @classmethod
 70    @abc.abstractmethod
 71    def default_config(cls) -> FieldConfigType:
 72        """Returns the default field config for a given field type."""
 73
 74    @classmethod
 75    @abc.abstractmethod
 76    def read_only(cls) -> bool:
 77        """
 78        Read only fields (like modification date or UUID fields) will be ignored
 79        during update calls like `Table.update()`.
 80        """
 81
 82    _pending_changes: list[str] = []
 83    """See documentation of `BaserowField.register_pending_changes()`."""
 84
 85    def register_pending_change(self, description: str):
 86        """
 87        Registers a change to the field, which is currently only stored locally
 88        and must be explicitly applied to Baserow using `Table.update()`.
 89
 90        Args:
 91            description (str): A description of the change in data.
 92        """
 93        self._pending_changes.append(description)
 94
 95    def changes_applied(self):
 96        """
 97        Is called by `Table.update()` after all pending changes have been
 98        written to Baserow.
 99        """
100        self._pending_changes = []
101
102    def __del__(self):
103        if len(self._pending_changes) != 0:
104            changes = ["- " + change for change in self._pending_changes]
105            print(f"WARNING: THERE ARE STILL PENDING CHANGES IN FIELD {self.__class__.__name__}")  # noqa: F821
106            print("\n".join(changes))
107            print(
108                "It looks like `Table.update()` was not called to apply these changes to Baserow.",
109            )

Abstract base class for all Baserow fields that are not covered by the built-in types.

This class also handles tracking changes, which are initially local and only applied to Baserow when Table.update() is called. For example, the method TableLinkField.append() adds a new link to a record, but this change is only written to Baserow when Table.update() is invoked. Such actions can be registered with BaserowField.register_pending_change(). If an object with pending changes is deleted (__del__), a corresponding warning is issued.

@classmethod
@abc.abstractmethod
def read_only(cls) -> bool:
74    @classmethod
75    @abc.abstractmethod
76    def read_only(cls) -> bool:
77        """
78        Read only fields (like modification date or UUID fields) will be ignored
79        during update calls like `Table.update()`.
80        """

Read only fields (like modification date or UUID fields) will be ignored during update calls like Table.update().

def register_pending_change(self, description: str):
85    def register_pending_change(self, description: str):
86        """
87        Registers a change to the field, which is currently only stored locally
88        and must be explicitly applied to Baserow using `Table.update()`.
89
90        Args:
91            description (str): A description of the change in data.
92        """
93        self._pending_changes.append(description)

Registers a change to the field, which is currently only stored locally and must be explicitly applied to Baserow using Table.update().

Arguments:
  • description (str): A description of the change in data.
def changes_applied(self):
 95    def changes_applied(self):
 96        """
 97        Is called by `Table.update()` after all pending changes have been
 98        written to Baserow.
 99        """
100        self._pending_changes = []

Is called by Table.update() after all pending changes have been written to Baserow.

model_config = {}
def model_post_init(self: pydantic.main.BaseModel, context: Any, /) -> None:
281def init_private_attributes(self: BaseModel, context: Any, /) -> None:
282    """This function is meant to behave like a BaseModel method to initialise private attributes.
283
284    It takes context as an argument since that's what pydantic-core passes when calling it.
285
286    Args:
287        self: The BaseModel instance.
288        context: The context.
289    """
290    if getattr(self, '__pydantic_private__', None) is None:
291        pydantic_private = {}
292        for name, private_attr in self.__private_attributes__.items():
293            default = private_attr.get_default()
294            if default is not PydanticUndefined:
295                pydantic_private[name] = default
296        object_setattr(self, '__pydantic_private__', pydantic_private)

This function is meant to behave like a BaseModel method to initialise private attributes.

It takes context as an argument since that's what pydantic-core passes when calling it.

Arguments:
  • self: The BaseModel instance.
  • context: The context.
model_fields = {}
model_computed_fields = {}
Inherited Members
pydantic.main.BaseModel
BaseModel
model_extra
model_fields_set
model_construct
model_copy
model_dump
model_dump_json
model_json_schema
model_parametrized_name
model_rebuild
model_validate
model_validate_json
model_validate_strings
dict
json
parse_obj
parse_raw
parse_file
from_orm
construct
copy
schema
schema_json
validate
update_forward_refs
class User(pydantic.main.BaseModel):
112class User(BaseModel):
113    """
114    A table field that contains one Baserow system user.
115    """
116    user_id: Optional[int] = Field(alias=str("id"))
117    name: Optional[str] = Field(alias=str("name"))

A table field that contains one Baserow system user.

user_id: Optional[int]
name: Optional[str]
model_config = {}
model_fields = {'user_id': FieldInfo(annotation=Union[int, NoneType], required=True, alias='id', alias_priority=2), 'name': FieldInfo(annotation=Union[str, NoneType], required=True, alias='name', alias_priority=2)}
model_computed_fields = {}
Inherited Members
pydantic.main.BaseModel
BaseModel
model_extra
model_fields_set
model_construct
model_copy
model_dump
model_dump_json
model_json_schema
model_parametrized_name
model_post_init
model_rebuild
model_validate
model_validate_json
model_validate_strings
dict
json
parse_obj
parse_raw
parse_file
from_orm
construct
copy
schema
schema_json
validate
update_forward_refs
class CreatedByField(User, BaserowField):
120class CreatedByField(User, BaserowField):
121    """
122    Field tracking the user who created an entry.
123    """
124    @classmethod
125    def default_config(cls) -> FieldConfigType:
126        return CreatedByFieldConfig()
127
128    @classmethod
129    def read_only(cls) -> bool:
130        return True

Field tracking the user who created an entry.

@classmethod
def read_only(cls) -> bool:
128    @classmethod
129    def read_only(cls) -> bool:
130        return True

Read only fields (like modification date or UUID fields) will be ignored during update calls like Table.update().

model_config = {}
def model_post_init(self: pydantic.main.BaseModel, context: Any, /) -> None:
105                    def wrapped_model_post_init(self: BaseModel, context: Any, /) -> None:
106                        """We need to both initialize private attributes and call the user-defined model_post_init
107                        method.
108                        """
109                        init_private_attributes(self, context)
110                        original_model_post_init(self, context)

We need to both initialize private attributes and call the user-defined model_post_init method.

model_fields = {'user_id': FieldInfo(annotation=Union[int, NoneType], required=True, alias='id', alias_priority=2), 'name': FieldInfo(annotation=Union[str, NoneType], required=True, alias='name', alias_priority=2)}
model_computed_fields = {}
Inherited Members
pydantic.main.BaseModel
BaseModel
model_extra
model_fields_set
model_construct
model_copy
model_dump
model_dump_json
model_json_schema
model_parametrized_name
model_rebuild
model_validate
model_validate_json
model_validate_strings
dict
json
parse_obj
parse_raw
parse_file
from_orm
construct
copy
schema
schema_json
validate
update_forward_refs
User
user_id
name
BaserowField
register_pending_change
changes_applied
class LastModifiedByField(User, BaserowField):
133class LastModifiedByField(User, BaserowField):
134    """
135    Field tracking the user who last modified a record.
136    """
137    @classmethod
138    def default_config(cls) -> FieldConfigType:
139        return LastModifiedByFieldConfig()
140
141    @classmethod
142    def read_only(cls) -> bool:
143        return True

Field tracking the user who last modified a record.

@classmethod
def read_only(cls) -> bool:
141    @classmethod
142    def read_only(cls) -> bool:
143        return True

Read only fields (like modification date or UUID fields) will be ignored during update calls like Table.update().

model_config = {}
def model_post_init(self: pydantic.main.BaseModel, context: Any, /) -> None:
105                    def wrapped_model_post_init(self: BaseModel, context: Any, /) -> None:
106                        """We need to both initialize private attributes and call the user-defined model_post_init
107                        method.
108                        """
109                        init_private_attributes(self, context)
110                        original_model_post_init(self, context)

We need to both initialize private attributes and call the user-defined model_post_init method.

model_fields = {'user_id': FieldInfo(annotation=Union[int, NoneType], required=True, alias='id', alias_priority=2), 'name': FieldInfo(annotation=Union[str, NoneType], required=True, alias='name', alias_priority=2)}
model_computed_fields = {}
Inherited Members
pydantic.main.BaseModel
BaseModel
model_extra
model_fields_set
model_construct
model_copy
model_dump
model_dump_json
model_json_schema
model_parametrized_name
model_rebuild
model_validate
model_validate_json
model_validate_strings
dict
json
parse_obj
parse_raw
parse_file
from_orm
construct
copy
schema
schema_json
validate
update_forward_refs
User
user_id
name
BaserowField
register_pending_change
changes_applied
class CreatedOnField(pydantic.main.BaseModel, typing.Generic[~RootModelRootType]):
146class CreatedOnField(BaserowField, RootModel[datetime.datetime]):
147    """
148    Field containing the creation timestamp of a row.
149    """
150    root: datetime.datetime
151
152    @classmethod
153    def default_config(cls) -> FieldConfigType:
154        return CreatedOnFieldConfig()
155
156    @classmethod
157    def read_only(cls) -> bool:
158        return True

Field containing the creation timestamp of a row.

root: datetime.datetime
@classmethod
def read_only(cls) -> bool:
156    @classmethod
157    def read_only(cls) -> bool:
158        return True

Read only fields (like modification date or UUID fields) will be ignored during update calls like Table.update().

Inherited Members
pydantic.main.BaseModel
BaseModel
model_config
model_extra
model_fields_set
model_construct
model_copy
model_dump
model_dump_json
model_json_schema
model_parametrized_name
model_post_init
model_rebuild
model_validate
model_validate_json
model_validate_strings
dict
json
parse_obj
parse_raw
parse_file
from_orm
construct
copy
schema
schema_json
validate
update_forward_refs
model_fields
model_computed_fields
BaserowField
register_pending_change
changes_applied
class LastModifiedOnField(pydantic.main.BaseModel, typing.Generic[~RootModelRootType]):
161class LastModifiedOnField(BaserowField, RootModel[datetime.datetime]):
162    """
163    Field containing the last modification timestamp of a row.
164    """
165    root: datetime.datetime
166
167    @classmethod
168    def default_config(cls) -> FieldConfigType:
169        return LastModifiedFieldConfig()
170
171    @classmethod
172    def read_only(cls) -> bool:
173        return True

Field containing the last modification timestamp of a row.

root: datetime.datetime
@classmethod
def read_only(cls) -> bool:
171    @classmethod
172    def read_only(cls) -> bool:
173        return True

Read only fields (like modification date or UUID fields) will be ignored during update calls like Table.update().

Inherited Members
pydantic.main.BaseModel
BaseModel
model_config
model_extra
model_fields_set
model_construct
model_copy
model_dump
model_dump_json
model_json_schema
model_parametrized_name
model_post_init
model_rebuild
model_validate
model_validate_json
model_validate_strings
dict
json
parse_obj
parse_raw
parse_file
from_orm
construct
copy
schema
schema_json
validate
update_forward_refs
model_fields
model_computed_fields
BaserowField
register_pending_change
changes_applied
class MultipleCollaboratorsField(pydantic.main.BaseModel, typing.Generic[~RootModelRootType]):
176class MultipleCollaboratorsField(BaserowField, RootModel[list[User]]):
177    """
178    A table field that contains one or multiple Baserow system user(s).
179    """
180    root: list[User]
181
182    @classmethod
183    def default_config(cls) -> FieldConfigType:
184        return MultipleCollaboratorsFieldConfig()
185
186    @classmethod
187    def read_only(cls) -> bool:
188        return False

A table field that contains one or multiple Baserow system user(s).

root: list[User]
@classmethod
def read_only(cls) -> bool:
186    @classmethod
187    def read_only(cls) -> bool:
188        return False

Read only fields (like modification date or UUID fields) will be ignored during update calls like Table.update().

Inherited Members
pydantic.main.BaseModel
BaseModel
model_config
model_extra
model_fields_set
model_construct
model_copy
model_dump
model_dump_json
model_json_schema
model_parametrized_name
model_post_init
model_rebuild
model_validate
model_validate_json
model_validate_strings
dict
json
parse_obj
parse_raw
parse_file
from_orm
construct
copy
schema
schema_json
validate
update_forward_refs
model_fields
model_computed_fields
BaserowField
register_pending_change
changes_applied
class FileField(pydantic.main.BaseModel, typing.Generic[~RootModelRootType]):
191class FileField(BaserowField, RootModel[list[File]]):
192    """
193    A file field allows you to easily upload one or more files from your device
194    or from a URL.
195    """
196    root: list[File]
197
198    @classmethod
199    def default_config(cls) -> FieldConfigType:
200        return FileFieldConfig()
201
202    @classmethod
203    def read_only(cls) -> bool:
204        return False
205
206    @classmethod
207    async def from_file(
208        cls,
209        file: BufferedReader | str | Path,
210        name: Optional[str] = None,
211        client: Optional[Client] = None,
212    ):
213        """
214        This method takes a local file (either as a `BufferedReader` or as a
215        path) and uploads it to Baserow's media storage, handling the linkage
216        between the field and the stored file. A `FileField` instance containing
217        the uploaded file is returned. Calling this method initiates the file
218        upload, which may take some time depending on the file size.
219
220        Note that this method does not use the client associated with the table.
221
222        ```python
223        # By path.
224        await Book(
225            cover=await FileField.from_file("path/to/image.png"),
226        ).create()
227
228        # With BufferedReader.
229        await Book(
230            cover=await FileField.from_file(open("path/to/image.png", "rb")),
231        ).create()
232        ```
233
234        Args:
235            file (BufferedReader | str | Path): File to be uploaded.
236            name (str | None): Optional human-readable name of the file, as it
237                should be displayed in the Baserow frontend.
238            client (Client | None): Specifies which API client should be used.
239                If none is provided, the `GlobalClient` will be used. Note that
240                this method does not automatically use the client associated
241                with the table.
242        """
243        rsl = cls(root=[])
244        await rsl.append_file(file, name, client, register_pending_change=False)
245        return rsl
246
247    @classmethod
248    async def from_url(
249        cls,
250        url: str,
251        name: Optional[str] = None,
252        client: Optional[Client] = None,
253    ):
254        """
255        This method takes the URL of a publicly accessible file on the internet
256        and uploads it to Baserow's media storage, managing the linkage between
257        the field and the stored file. Calling this method initiates the file
258        upload, which may take some time depending on the file size.
259
260        Note that this method does not use the client associated with the table.
261
262        ```python
263        await Book(
264            cover=await FileField.from_url("https://example.com/image.png"),
265        ).create()
266        ```
267
268        Args:
269            url (str): URL of the file to be uploaded.
270            name (str | None): Optional human-readable name of the file, as it
271                should be displayed in the Baserow frontend.
272            client (Client | None): Specifies which API client should be used.
273                If none is provided, the `GlobalClient` will be used. Note that
274                this method does not automatically use the client associated
275                with the table.
276        """
277        rsl = cls(root=[])
278        await rsl.append_file_from_url(url, name, client, register_pending_change=False)
279        return rsl
280
281    async def append_file(
282        self,
283        file: BufferedReader | str | Path,
284        name: Optional[str] = None,
285        client: Optional[Client] = None,
286        register_pending_change: bool = True,
287    ):
288        """
289        This method takes a local file (either as a `BufferedReader` or as a
290        path) and uploads it to Baserow's media storage and adds it to the file
291        field.Calling this method initiates the file upload, which may take some
292        time depending on the file size.
293
294        Further information about uploading and setting files can be found in
295        the documentation of `client.upload_file()`. After this method
296        `Table.update()` must be called manually to apply the changes.
297
298        ```python
299        book = Book.by_id(ROW_ID)
300
301        # By path.
302        await book.cover.append_file("path/to/image.png")
303
304        # With BufferedReader.
305        await book.cover.append_file(open("path/to/image.png", "rb"))
306
307        book.update()
308        ```
309
310        Args:
311            file (BufferedReader | str | Path): File to be uploaded.
312            name (str | None): Optional human-readable name of the file, as it
313                should be displayed in the Baserow frontend.
314            client (Client | None): Specifies which API client should be used.
315                If none is provided, the `GlobalClient` will be used. Note that
316                this method does not automatically use the client associated
317                with the table.
318            register_pending_change (bool): Internal option for the
319                `FileField.from_file()` and `FileField.from_url()` methods. When
320                set to false, tracking of pending changes for this call is
321                disabled. This is only useful in situations where
322                `Table.update()` will be called anyway, such as when the method
323                is invoked within the initialization of a model.
324        """
325        if not isinstance(file, BufferedReader):
326            file = open(file, "rb")
327        if client is None:
328            client = GlobalClient()
329        new_file = await client.upload_file(file)
330        if name is not None:
331            new_file.original_name = name
332        self.root.append(new_file)
333        if register_pending_change:
334            self.register_pending_change(
335                f"file '{new_file.original_name}' added",
336            )
337
338    async def append_file_from_url(
339        self,
340        url: str,
341        name: Optional[str] = None,
342        client: Optional[Client] = None,
343        register_pending_change: bool = True,
344    ):
345        """
346        This method takes the URL of a publicly accessible file on the internet
347        and uploads it to Baserow's media storage and adds it to the file
348        field.Calling this method initiates the file upload, which may take some
349        time depending on the file size.
350
351        Further information about uploading and setting files can be found in
352        the documentation of `client.upload_file()`. After this method
353        `Table.update()` must be called manually to apply the changes.
354
355        ```python
356        book = Book.by_id(ROW_ID)
357        await book.cover.append_file_from_url("https://example.com/image.png")
358        book.update()
359        ```
360
361        Args:
362            url (str): The URL of the file.
363            name (str | None): Optional human-readable name of the file, as it
364                should be displayed in the Baserow frontend.
365            client (Client | None): Specifies which API client should be used.
366                If none is provided, the `GlobalClient` will be used. Note that
367                this method does not automatically use the client associated
368                with the table.
369            register_pending_change (bool): Internal option for the
370                `FileField.from_file()` and `FileField.from_url()` methods. When
371                set to false, tracking of pending changes for this call is
372                disabled. This is only useful in situations where
373                `Table.update()` will be called anyway, such as when the method
374                is invoked within the initialization of a model.
375        """
376        if client is None:
377            client = GlobalClient()
378        new_file = await client.upload_file_via_url(url)
379        if name is not None:
380            new_file.original_name = name
381        self.root.append(new_file)
382        if register_pending_change:
383            self.register_pending_change(f"file from url '{url}' added")
384
385    def clear(self):
386        """
387        Removes all files from field. After that, `Table.update()` must be called
388        to apply the changes.
389
390        ```python
391        book = Book.by_id(ROW_ID)
392        await book.cover.clear()
393        book.update()
394        ```
395        """
396        self.root.clear()
397        self.register_pending_change("remove all files in field")

A file field allows you to easily upload one or more files from your device or from a URL.

root: list[baserow.file.File]
@classmethod
def read_only(cls) -> bool:
202    @classmethod
203    def read_only(cls) -> bool:
204        return False

Read only fields (like modification date or UUID fields) will be ignored during update calls like Table.update().

@classmethod
async def from_file( cls, file: _io.BufferedReader | str | pathlib.Path, name: Optional[str] = None, client: Optional[baserow.client.Client] = None):
206    @classmethod
207    async def from_file(
208        cls,
209        file: BufferedReader | str | Path,
210        name: Optional[str] = None,
211        client: Optional[Client] = None,
212    ):
213        """
214        This method takes a local file (either as a `BufferedReader` or as a
215        path) and uploads it to Baserow's media storage, handling the linkage
216        between the field and the stored file. A `FileField` instance containing
217        the uploaded file is returned. Calling this method initiates the file
218        upload, which may take some time depending on the file size.
219
220        Note that this method does not use the client associated with the table.
221
222        ```python
223        # By path.
224        await Book(
225            cover=await FileField.from_file("path/to/image.png"),
226        ).create()
227
228        # With BufferedReader.
229        await Book(
230            cover=await FileField.from_file(open("path/to/image.png", "rb")),
231        ).create()
232        ```
233
234        Args:
235            file (BufferedReader | str | Path): File to be uploaded.
236            name (str | None): Optional human-readable name of the file, as it
237                should be displayed in the Baserow frontend.
238            client (Client | None): Specifies which API client should be used.
239                If none is provided, the `GlobalClient` will be used. Note that
240                this method does not automatically use the client associated
241                with the table.
242        """
243        rsl = cls(root=[])
244        await rsl.append_file(file, name, client, register_pending_change=False)
245        return rsl

This method takes a local file (either as a BufferedReader or as a path) and uploads it to Baserow's media storage, handling the linkage between the field and the stored file. A FileField instance containing the uploaded file is returned. Calling this method initiates the file upload, which may take some time depending on the file size.

Note that this method does not use the client associated with the table.

# By path.
await Book(
    cover=await FileField.from_file("path/to/image.png"),
).create()

# With BufferedReader.
await Book(
    cover=await FileField.from_file(open("path/to/image.png", "rb")),
).create()
Arguments:
  • file (BufferedReader | str | Path): File to be uploaded.
  • name (str | None): Optional human-readable name of the file, as it should be displayed in the Baserow frontend.
  • client (Client | None): Specifies which API client should be used. If none is provided, the GlobalClient will be used. Note that this method does not automatically use the client associated with the table.
@classmethod
async def from_url( cls, url: str, name: Optional[str] = None, client: Optional[baserow.client.Client] = None):
247    @classmethod
248    async def from_url(
249        cls,
250        url: str,
251        name: Optional[str] = None,
252        client: Optional[Client] = None,
253    ):
254        """
255        This method takes the URL of a publicly accessible file on the internet
256        and uploads it to Baserow's media storage, managing the linkage between
257        the field and the stored file. Calling this method initiates the file
258        upload, which may take some time depending on the file size.
259
260        Note that this method does not use the client associated with the table.
261
262        ```python
263        await Book(
264            cover=await FileField.from_url("https://example.com/image.png"),
265        ).create()
266        ```
267
268        Args:
269            url (str): URL of the file to be uploaded.
270            name (str | None): Optional human-readable name of the file, as it
271                should be displayed in the Baserow frontend.
272            client (Client | None): Specifies which API client should be used.
273                If none is provided, the `GlobalClient` will be used. Note that
274                this method does not automatically use the client associated
275                with the table.
276        """
277        rsl = cls(root=[])
278        await rsl.append_file_from_url(url, name, client, register_pending_change=False)
279        return rsl

This method takes the URL of a publicly accessible file on the internet and uploads it to Baserow's media storage, managing the linkage between the field and the stored file. Calling this method initiates the file upload, which may take some time depending on the file size.

Note that this method does not use the client associated with the table.

await Book(
    cover=await FileField.from_url("https://example.com/image.png"),
).create()
Arguments:
  • url (str): URL of the file to be uploaded.
  • name (str | None): Optional human-readable name of the file, as it should be displayed in the Baserow frontend.
  • client (Client | None): Specifies which API client should be used. If none is provided, the GlobalClient will be used. Note that this method does not automatically use the client associated with the table.
async def append_file( self, file: _io.BufferedReader | str | pathlib.Path, name: Optional[str] = None, client: Optional[baserow.client.Client] = None, register_pending_change: bool = True):
281    async def append_file(
282        self,
283        file: BufferedReader | str | Path,
284        name: Optional[str] = None,
285        client: Optional[Client] = None,
286        register_pending_change: bool = True,
287    ):
288        """
289        This method takes a local file (either as a `BufferedReader` or as a
290        path) and uploads it to Baserow's media storage and adds it to the file
291        field.Calling this method initiates the file upload, which may take some
292        time depending on the file size.
293
294        Further information about uploading and setting files can be found in
295        the documentation of `client.upload_file()`. After this method
296        `Table.update()` must be called manually to apply the changes.
297
298        ```python
299        book = Book.by_id(ROW_ID)
300
301        # By path.
302        await book.cover.append_file("path/to/image.png")
303
304        # With BufferedReader.
305        await book.cover.append_file(open("path/to/image.png", "rb"))
306
307        book.update()
308        ```
309
310        Args:
311            file (BufferedReader | str | Path): File to be uploaded.
312            name (str | None): Optional human-readable name of the file, as it
313                should be displayed in the Baserow frontend.
314            client (Client | None): Specifies which API client should be used.
315                If none is provided, the `GlobalClient` will be used. Note that
316                this method does not automatically use the client associated
317                with the table.
318            register_pending_change (bool): Internal option for the
319                `FileField.from_file()` and `FileField.from_url()` methods. When
320                set to false, tracking of pending changes for this call is
321                disabled. This is only useful in situations where
322                `Table.update()` will be called anyway, such as when the method
323                is invoked within the initialization of a model.
324        """
325        if not isinstance(file, BufferedReader):
326            file = open(file, "rb")
327        if client is None:
328            client = GlobalClient()
329        new_file = await client.upload_file(file)
330        if name is not None:
331            new_file.original_name = name
332        self.root.append(new_file)
333        if register_pending_change:
334            self.register_pending_change(
335                f"file '{new_file.original_name}' added",
336            )

This method takes a local file (either as a BufferedReader or as a path) and uploads it to Baserow's media storage and adds it to the file field.Calling this method initiates the file upload, which may take some time depending on the file size.

Further information about uploading and setting files can be found in the documentation of client.upload_file(). After this method Table.update() must be called manually to apply the changes.

book = Book.by_id(ROW_ID)

# By path.
await book.cover.append_file("path/to/image.png")

# With BufferedReader.
await book.cover.append_file(open("path/to/image.png", "rb"))

book.update()
Arguments:
  • file (BufferedReader | str | Path): File to be uploaded.
  • name (str | None): Optional human-readable name of the file, as it should be displayed in the Baserow frontend.
  • client (Client | None): Specifies which API client should be used. If none is provided, the GlobalClient will be used. Note that this method does not automatically use the client associated with the table.
  • register_pending_change (bool): Internal option for the FileField.from_file() and FileField.from_url() methods. When set to false, tracking of pending changes for this call is disabled. This is only useful in situations where Table.update() will be called anyway, such as when the method is invoked within the initialization of a model.
async def append_file_from_url( self, url: str, name: Optional[str] = None, client: Optional[baserow.client.Client] = None, register_pending_change: bool = True):
338    async def append_file_from_url(
339        self,
340        url: str,
341        name: Optional[str] = None,
342        client: Optional[Client] = None,
343        register_pending_change: bool = True,
344    ):
345        """
346        This method takes the URL of a publicly accessible file on the internet
347        and uploads it to Baserow's media storage and adds it to the file
348        field.Calling this method initiates the file upload, which may take some
349        time depending on the file size.
350
351        Further information about uploading and setting files can be found in
352        the documentation of `client.upload_file()`. After this method
353        `Table.update()` must be called manually to apply the changes.
354
355        ```python
356        book = Book.by_id(ROW_ID)
357        await book.cover.append_file_from_url("https://example.com/image.png")
358        book.update()
359        ```
360
361        Args:
362            url (str): The URL of the file.
363            name (str | None): Optional human-readable name of the file, as it
364                should be displayed in the Baserow frontend.
365            client (Client | None): Specifies which API client should be used.
366                If none is provided, the `GlobalClient` will be used. Note that
367                this method does not automatically use the client associated
368                with the table.
369            register_pending_change (bool): Internal option for the
370                `FileField.from_file()` and `FileField.from_url()` methods. When
371                set to false, tracking of pending changes for this call is
372                disabled. This is only useful in situations where
373                `Table.update()` will be called anyway, such as when the method
374                is invoked within the initialization of a model.
375        """
376        if client is None:
377            client = GlobalClient()
378        new_file = await client.upload_file_via_url(url)
379        if name is not None:
380            new_file.original_name = name
381        self.root.append(new_file)
382        if register_pending_change:
383            self.register_pending_change(f"file from url '{url}' added")

This method takes the URL of a publicly accessible file on the internet and uploads it to Baserow's media storage and adds it to the file field.Calling this method initiates the file upload, which may take some time depending on the file size.

Further information about uploading and setting files can be found in the documentation of client.upload_file(). After this method Table.update() must be called manually to apply the changes.

book = Book.by_id(ROW_ID)
await book.cover.append_file_from_url("https://example.com/image.png")
book.update()
Arguments:
  • url (str): The URL of the file.
  • name (str | None): Optional human-readable name of the file, as it should be displayed in the Baserow frontend.
  • client (Client | None): Specifies which API client should be used. If none is provided, the GlobalClient will be used. Note that this method does not automatically use the client associated with the table.
  • register_pending_change (bool): Internal option for the FileField.from_file() and FileField.from_url() methods. When set to false, tracking of pending changes for this call is disabled. This is only useful in situations where Table.update() will be called anyway, such as when the method is invoked within the initialization of a model.
def clear(self):
385    def clear(self):
386        """
387        Removes all files from field. After that, `Table.update()` must be called
388        to apply the changes.
389
390        ```python
391        book = Book.by_id(ROW_ID)
392        await book.cover.clear()
393        book.update()
394        ```
395        """
396        self.root.clear()
397        self.register_pending_change("remove all files in field")

Removes all files from field. After that, Table.update() must be called to apply the changes.

book = Book.by_id(ROW_ID)
await book.cover.clear()
book.update()
Inherited Members
pydantic.main.BaseModel
BaseModel
model_config
model_extra
model_fields_set
model_construct
model_copy
model_dump
model_dump_json
model_json_schema
model_parametrized_name
model_post_init
model_rebuild
model_validate
model_validate_json
model_validate_strings
dict
json
parse_obj
parse_raw
parse_file
from_orm
construct
copy
schema
schema_json
validate
update_forward_refs
model_fields
model_computed_fields
BaserowField
register_pending_change
changes_applied
SelectEnum = ~SelectEnum

Instances of a SelectEntry have to be bound to a enum which contain the possible values of the select entry.

class SelectEntry(pydantic.main.BaseModel, typing.Generic[~SelectEnum]):
407class SelectEntry(BaseModel, Generic[SelectEnum]):
408    """A entry in a single or multiple select field."""
409    entry_id: Optional[int] = Field(default=None, alias="id")
410    value: Optional[SelectEnum] = None
411    color: Optional[str] = None
412
413    model_config = ConfigDict(populate_by_name=True)
414
415    @model_validator(mode="after")
416    def id_or_value_must_be_set(self: "SelectEntry") -> "SelectEntry":
417        if self.entry_id is None and self.value is None:
418            raise ValueError(
419                "At least one of the entry_id and value fields must be set"
420            )
421        return self
422
423    @model_serializer
424    def serialize(self) -> Union[int, str]:
425        """
426        Serializes the field into the data structure required by the Baserow
427        API. If an entry has both an id and a value set, the id is used.
428        Otherwise the set field is used.
429
430        From the Baserow API documentation: Accepts an integer or a text value
431        representing the chosen select option id or option value. A null value
432        means none is selected. In case of a text value, the first matching
433        option is selected. 
434        """
435        if self.entry_id is not None:
436            return self.entry_id
437        if self.value is not None:
438            return self.value.value
439        raise ValueError("both fields id and value are unset for this entry")
440
441    @classmethod
442    def _get_all_possible_values(cls) -> list[str]:
443        metadata = cls.__pydantic_generic_metadata__
444        if "args" not in metadata:
445            raise PydanticGenericMetadataError.args_missing(
446                cls.__class__.__name__,
447                "select entry enum",
448            )
449        if len(metadata["args"]) < 1:
450            raise PydanticGenericMetadataError.args_empty(
451                cls.__class__.__name__,
452                "select entry enum",
453            )
454        select_enum = metadata["args"][0]
455        return [item.value for item in select_enum]
456
457    @classmethod
458    def _options_config(cls) -> list[SelectEntryConfig]:
459        rsl: list[SelectEntryConfig] = []
460        color_sequence = ColorSequence()
461        i = 0
462        for value in cls._get_all_possible_values():
463            rsl.append(SelectEntryConfig(
464                id=i,
465                value=value,
466                color=color_sequence.get_color(),
467            ))
468            i += 1
469        return rsl

A entry in a single or multiple select field.

entry_id: Optional[int]
value: Optional[~SelectEnum]
color: Optional[str]
@model_validator(mode='after')
def id_or_value_must_be_set(self: SelectEntry) -> SelectEntry:
415    @model_validator(mode="after")
416    def id_or_value_must_be_set(self: "SelectEntry") -> "SelectEntry":
417        if self.entry_id is None and self.value is None:
418            raise ValueError(
419                "At least one of the entry_id and value fields must be set"
420            )
421        return self
@model_serializer
def serialize(self) -> Union[int, str]:
423    @model_serializer
424    def serialize(self) -> Union[int, str]:
425        """
426        Serializes the field into the data structure required by the Baserow
427        API. If an entry has both an id and a value set, the id is used.
428        Otherwise the set field is used.
429
430        From the Baserow API documentation: Accepts an integer or a text value
431        representing the chosen select option id or option value. A null value
432        means none is selected. In case of a text value, the first matching
433        option is selected. 
434        """
435        if self.entry_id is not None:
436            return self.entry_id
437        if self.value is not None:
438            return self.value.value
439        raise ValueError("both fields id and value are unset for this entry")

Serializes the field into the data structure required by the Baserow API. If an entry has both an id and a value set, the id is used. Otherwise the set field is used.

From the Baserow API documentation: Accepts an integer or a text value representing the chosen select option id or option value. A null value means none is selected. In case of a text value, the first matching option is selected.

Inherited Members
pydantic.main.BaseModel
BaseModel
model_config
model_extra
model_fields_set
model_construct
model_copy
model_dump
model_dump_json
model_json_schema
model_parametrized_name
model_post_init
model_rebuild
model_validate
model_validate_json
model_validate_strings
dict
json
parse_obj
parse_raw
parse_file
from_orm
construct
copy
schema
schema_json
validate
update_forward_refs
model_fields
model_computed_fields
class SingleSelectField(pydantic.main.BaseModel, typing.Generic[~SelectEnum]):
472class SingleSelectField(SelectEntry[SelectEnum], BaserowField):
473    """Single select field in a table."""
474    @classmethod
475    def default_config(cls) -> FieldConfigType:
476        options = super(SingleSelectField, cls)._options_config()
477        return SingleSelectFieldConfig(select_options=options)
478
479    @classmethod
480    def read_only(cls) -> bool:
481        return False
482
483    @classmethod
484    def from_enum(cls, select_enum: SelectEnum):
485        """
486        This function can be used to directly obtain the correct instance of the
487        field abstraction from an enum. Primarily, this function is a quality of
488        life feature for directly setting a field value in a model
489        initialization. This replaces the somewhat unergonomic and unintuitive
490        syntax which would be used otherwise.
491
492        ```python
493        class Genre(str, enum.Enum):
494            FICTION = "Fiction"
495            EDUCATION = "Education"
496
497        class Book(Table):
498            [...]
499            genre: Optional[SingleSelectField[Genre]] = Field(default=None)
500
501        # Can use this...
502        await Book(
503            genre=SingleSelectField.from_enum(Genre.FICTION),
504        ).create()
505
506        # ...instead of
507        await Book(
508            genre=SingleSelectField[Genre](value=Genre.FICTION)
509        ).create()
510        ```
511
512        Args:
513            select_enum (SelectEnum): Enum to which the field should be set.add 
514        """
515        return SingleSelectField[type(select_enum)](value=select_enum)
516
517    def set(self, instance: SelectEnum):
518        """
519        Set the value of the field. Please note that this method does not update
520        the record on Baserow. You have to call `Table.update()` afterwards.
521
522        Args:
523            instance (SelectEnum): The enum which should be set in this field.
524        """
525        self.entry_id = None
526        self.value = instance
527        self.color = None
528        self.register_pending_change(f"set SingleSelect to '{instance.value}'")

Single select field in a table.

474    @classmethod
475    def default_config(cls) -> FieldConfigType:
476        options = super(SingleSelectField, cls)._options_config()
477        return SingleSelectFieldConfig(select_options=options)

Returns the default field config for a given field type.

@classmethod
def read_only(cls) -> bool:
479    @classmethod
480    def read_only(cls) -> bool:
481        return False

Read only fields (like modification date or UUID fields) will be ignored during update calls like Table.update().

@classmethod
def from_enum(cls, select_enum: ~SelectEnum):
483    @classmethod
484    def from_enum(cls, select_enum: SelectEnum):
485        """
486        This function can be used to directly obtain the correct instance of the
487        field abstraction from an enum. Primarily, this function is a quality of
488        life feature for directly setting a field value in a model
489        initialization. This replaces the somewhat unergonomic and unintuitive
490        syntax which would be used otherwise.
491
492        ```python
493        class Genre(str, enum.Enum):
494            FICTION = "Fiction"
495            EDUCATION = "Education"
496
497        class Book(Table):
498            [...]
499            genre: Optional[SingleSelectField[Genre]] = Field(default=None)
500
501        # Can use this...
502        await Book(
503            genre=SingleSelectField.from_enum(Genre.FICTION),
504        ).create()
505
506        # ...instead of
507        await Book(
508            genre=SingleSelectField[Genre](value=Genre.FICTION)
509        ).create()
510        ```
511
512        Args:
513            select_enum (SelectEnum): Enum to which the field should be set.add 
514        """
515        return SingleSelectField[type(select_enum)](value=select_enum)

This function can be used to directly obtain the correct instance of the field abstraction from an enum. Primarily, this function is a quality of life feature for directly setting a field value in a model initialization. This replaces the somewhat unergonomic and unintuitive syntax which would be used otherwise.

class Genre(str, enum.Enum):
    FICTION = "Fiction"
    EDUCATION = "Education"

class Book(Table):
    [...]
    genre: Optional[SingleSelectField[Genre]] = Field(default=None)

# Can use this...
await Book(
    genre=SingleSelectField.from_enum(Genre.FICTION),
).create()

# ...instead of
await Book(
    genre=SingleSelectField[Genre](value=Genre.FICTION)
).create()
Arguments:
  • select_enum (SelectEnum): Enum to which the field should be set.add
def set(self, instance: ~SelectEnum):
517    def set(self, instance: SelectEnum):
518        """
519        Set the value of the field. Please note that this method does not update
520        the record on Baserow. You have to call `Table.update()` afterwards.
521
522        Args:
523            instance (SelectEnum): The enum which should be set in this field.
524        """
525        self.entry_id = None
526        self.value = instance
527        self.color = None
528        self.register_pending_change(f"set SingleSelect to '{instance.value}'")

Set the value of the field. Please note that this method does not update the record on Baserow. You have to call Table.update() afterwards.

Arguments:
  • instance (SelectEnum): The enum which should be set in this field.
Inherited Members
pydantic.main.BaseModel
BaseModel
model_config
model_extra
model_fields_set
model_construct
model_copy
model_dump
model_dump_json
model_json_schema
model_parametrized_name
model_post_init
model_rebuild
model_validate
model_validate_json
model_validate_strings
dict
json
parse_obj
parse_raw
parse_file
from_orm
construct
copy
schema
schema_json
validate
update_forward_refs
model_fields
model_computed_fields
SelectEntry
entry_id
value
color
id_or_value_must_be_set
serialize
BaserowField
register_pending_change
changes_applied
class MultipleSelectField(BaserowField, pydantic.root_model.RootModel[list[SelectEntry]], typing.Generic[~SelectEnum]):
531class MultipleSelectField(BaserowField, RootModel[list[SelectEntry]], Generic[SelectEnum]):
532    """Multiple select field in a table."""
533    root: list[SelectEntry[SelectEnum]]
534
535    @classmethod
536    def read_only(cls) -> bool:
537        return False
538
539    @classmethod
540    def from_enums(cls, *select_enums: SelectEnum):
541        """
542        This function can be used to directly obtain the correct instance of the
543        field abstraction from one or multiple enum(s). Primarily, this function
544        is a quality of life feature for directly setting a field value in a
545        model initialization. This replaces the somewhat unergonomic and
546        unintuitive syntax which would be used otherwise.
547
548        ```python
549        class Keyword(str, enum.Enum):
550            ADVENTURE = "Adventure"
551            FICTION = "Fiction"
552            TECH = "Text"
553
554        class Book(Table):
555            [...]
556            keywords: Optional[MultipleSelectField[Keyword]] = Field(default=None)
557
558        await Book(
559            keywords=MultipleSelectField.from_enums(Keyword.ADVENTURE, Keyword.FICTION)
560        ).create()
561        ```
562
563        Args:
564            *select_enum (SelectEnum | list[SelectEnum]): Enum(s) value(s) to be part
565                of the select field.
566        """
567        if not select_enums:
568            raise ValueError("At least one enum must be provided")
569        select_enum_type = type(select_enums[0])
570        enums: list[SelectEntry[SelectEnum]] = []
571        for enum in select_enums:
572            enums.append(SelectEntry[type(enum)](value=enum))
573        return MultipleSelectField[select_enum_type](root=enums)
574
575    def append(self, *select_enums: SelectEnum):
576        """
577        Append one or multiple enum(s) to the field. Please note that this
578        method does not update the record on Baserow. You have to call
579        `Table.update()` afterwards.
580
581        Args:
582            *select_enum (SelectEnum | list[SelectEnum]): Enum(s) value(s) to be
583                added the the select field.
584        """
585        names: list[str] = []
586        for enum in select_enums:
587            self.root.append(SelectEntry(value=enum))
588            names.append(enum.name)
589        self.register_pending_change(
590            f"append enum(s) {', '.join(names)} to multiple select field",
591        )
592
593    def clear(self):
594        """
595        Remove all enums currently set for this field. Please note that this
596        method does not update the record on Baserow. You have to call
597        `Table.update()` afterwards.
598        """
599        self.root.clear()
600        self.register_pending_change(
601            f"removed all enum(s) from multiple select field",
602        )
603
604    def remove(self, *select_enums: SelectEnum):
605        """
606        Remove one or multiple enum(s) from the field. Please note that this
607        method does not update the record on Baserow. You have to call
608        `Table.update()` afterwards.
609
610        Args:
611            *select_enum (SelectEnum | list[SelectEnum]): Enum(s) value(s) to be
612                removed the the select field.
613        """
614        to_be_removed = [
615            entry for entry in self.root if entry. value in select_enums]
616        self.root = [
617            entry for entry in self.root if entry not in to_be_removed
618        ]
619        names = [
620            entry.value.name for entry in to_be_removed if entry.value is not None]
621        self.register_pending_change(
622            f"removed enum(s) {', '.join(names)} from multiple select field",
623        )
624
625    @classmethod
626    def default_config(cls) -> FieldConfigType:
627        metadata = cls.__pydantic_generic_metadata__
628        if "args" not in metadata:
629            raise PydanticGenericMetadataError.args_missing(
630                cls.__class__.__name__,
631                "select entry enum",
632            )
633        if len(metadata["args"]) < 1:
634            raise PydanticGenericMetadataError.args_empty(
635                cls.__class__.__name__,
636                "select entry enum",
637            )
638        select_enum = metadata["args"][0]
639        rsl: list[SelectEntryConfig] = []
640        color_sequence = ColorSequence()
641        i = 0
642        for item in select_enum:
643            rsl.append(SelectEntryConfig(
644                id=i,
645                value=item.value,
646                color=color_sequence.get_color(),
647            ))
648            i += 1
649        return MultipleSelectFieldConfig(select_options=rsl)

Multiple select field in a table.

root: list[SelectEntry]
@classmethod
def from_enums(cls, *select_enums: ~SelectEnum):
539    @classmethod
540    def from_enums(cls, *select_enums: SelectEnum):
541        """
542        This function can be used to directly obtain the correct instance of the
543        field abstraction from one or multiple enum(s). Primarily, this function
544        is a quality of life feature for directly setting a field value in a
545        model initialization. This replaces the somewhat unergonomic and
546        unintuitive syntax which would be used otherwise.
547
548        ```python
549        class Keyword(str, enum.Enum):
550            ADVENTURE = "Adventure"
551            FICTION = "Fiction"
552            TECH = "Text"
553
554        class Book(Table):
555            [...]
556            keywords: Optional[MultipleSelectField[Keyword]] = Field(default=None)
557
558        await Book(
559            keywords=MultipleSelectField.from_enums(Keyword.ADVENTURE, Keyword.FICTION)
560        ).create()
561        ```
562
563        Args:
564            *select_enum (SelectEnum | list[SelectEnum]): Enum(s) value(s) to be part
565                of the select field.
566        """
567        if not select_enums:
568            raise ValueError("At least one enum must be provided")
569        select_enum_type = type(select_enums[0])
570        enums: list[SelectEntry[SelectEnum]] = []
571        for enum in select_enums:
572            enums.append(SelectEntry[type(enum)](value=enum))
573        return MultipleSelectField[select_enum_type](root=enums)

This function can be used to directly obtain the correct instance of the field abstraction from one or multiple enum(s). Primarily, this function is a quality of life feature for directly setting a field value in a model initialization. This replaces the somewhat unergonomic and unintuitive syntax which would be used otherwise.

class Keyword(str, enum.Enum):
    ADVENTURE = "Adventure"
    FICTION = "Fiction"
    TECH = "Text"

class Book(Table):
    [...]
    keywords: Optional[MultipleSelectField[Keyword]] = Field(default=None)

await Book(
    keywords=MultipleSelectField.from_enums(Keyword.ADVENTURE, Keyword.FICTION)
).create()
Arguments:
  • *select_enum (SelectEnum | list[SelectEnum]): Enum(s) value(s) to be part of the select field.
def append(self, *select_enums: ~SelectEnum):
575    def append(self, *select_enums: SelectEnum):
576        """
577        Append one or multiple enum(s) to the field. Please note that this
578        method does not update the record on Baserow. You have to call
579        `Table.update()` afterwards.
580
581        Args:
582            *select_enum (SelectEnum | list[SelectEnum]): Enum(s) value(s) to be
583                added the the select field.
584        """
585        names: list[str] = []
586        for enum in select_enums:
587            self.root.append(SelectEntry(value=enum))
588            names.append(enum.name)
589        self.register_pending_change(
590            f"append enum(s) {', '.join(names)} to multiple select field",
591        )

Append one or multiple enum(s) to the field. Please note that this method does not update the record on Baserow. You have to call Table.update() afterwards.

Arguments:
  • *select_enum (SelectEnum | list[SelectEnum]): Enum(s) value(s) to be added the the select field.
def clear(self):
593    def clear(self):
594        """
595        Remove all enums currently set for this field. Please note that this
596        method does not update the record on Baserow. You have to call
597        `Table.update()` afterwards.
598        """
599        self.root.clear()
600        self.register_pending_change(
601            f"removed all enum(s) from multiple select field",
602        )

Remove all enums currently set for this field. Please note that this method does not update the record on Baserow. You have to call Table.update() afterwards.

def remove(self, *select_enums: ~SelectEnum):
604    def remove(self, *select_enums: SelectEnum):
605        """
606        Remove one or multiple enum(s) from the field. Please note that this
607        method does not update the record on Baserow. You have to call
608        `Table.update()` afterwards.
609
610        Args:
611            *select_enum (SelectEnum | list[SelectEnum]): Enum(s) value(s) to be
612                removed the the select field.
613        """
614        to_be_removed = [
615            entry for entry in self.root if entry. value in select_enums]
616        self.root = [
617            entry for entry in self.root if entry not in to_be_removed
618        ]
619        names = [
620            entry.value.name for entry in to_be_removed if entry.value is not None]
621        self.register_pending_change(
622            f"removed enum(s) {', '.join(names)} from multiple select field",
623        )

Remove one or multiple enum(s) from the field. Please note that this method does not update the record on Baserow. You have to call Table.update() afterwards.

Arguments:
  • *select_enum (SelectEnum | list[SelectEnum]): Enum(s) value(s) to be removed the the select field.
Inherited Members
pydantic.root_model.RootModel
RootModel
model_construct
BaserowField
default_config
read_only
register_pending_change
changes_applied
model_config
model_post_init
model_fields
model_computed_fields
pydantic.main.BaseModel
model_extra
model_fields_set
model_copy
model_dump
model_dump_json
model_json_schema
model_parametrized_name
model_rebuild
model_validate
model_validate_json
model_validate_strings
dict
json
parse_obj
parse_raw
parse_file
from_orm
construct
copy
schema
schema_json
validate
update_forward_refs