Перейти к содержанию

Поля и типы данных

Типы данных

Прежде чем мы продолжим модифицировать наш класс Points, углубимся в техническую часть и разберёмся, как Sqlite3 API хранит данные.

Стандартные типы данных

К стандартным типам данных относятся str и int, которые мы уже использовали при описании полей в таблице Points. Этих всем известных типов данных нет в синтаксисе Sqlite, поэтому API переводит привычный для питонистов str в привычный для Sqlite TEXT, а int в INTEGER и обратно соответственно.

Пользовательские типы данных

Известно, что в Sqlite есть 4 основных типа данных, это: INTEGER, TEXT, BLOB и REAL.
Поэтому, чтобы хранить например списки и словари, были реализованы пользовательские типы данных. Они находятся в файле tupes.py.

Пример использования пользовательских типов данных

from sqlite3_api.Table import Table
from sqlite3_api.field_types import List


class Students(Table):
    first_name: str
    last_name: str
    age: int
    marks: List

В данном случае поле marks будет представлено в виде списка, а так же будет иметь все свойства и методы стандартного для питона типа данных list

Таблица типов данных

Тип данных str int List Dict
Расшифровка TEXT INTEGER list dict

Создание пользовательских типов данных

Умение создавать пользовательские типы данных — полезное умение, так как пользовательские типы данных значительно облегчают хранение и использование данных, тип которых не поддерживает Sqlite.

Давайте научимся на примере.
Создадим тип данных, который будет хранить координаты на двумерной плоскости.

from sqlite3_api.field_types import CustomType


class Position(CustomType):
    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y

    @staticmethod
    def adapter(obj) -> bytes:
        return ('%f;%f' % (obj.x, obj.y)).encode('ascii')

    def converter(self, obj: bytes):
        return Position(*map(float, obj.split(b";")))

Разберёмся как мы это сделали.


Импортируем инструмент для создания своих типов данных.

from sqlite3_api.field_types import CustomType


Создаем класс, родителем которого является CustomType.

class Position(CustomType):
    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y

    @staticmethod
    def adapter(obj) -> bytes:
        return ('%f;%f' % (obj.x, obj.y)).encode('ascii')

    def converter(self, obj: bytes):
        return Position(*map(float, obj.split(b";")))


Добавляем конструктор класса и определяем атрибуты x и y — координаты.

class Position(CustomType):
    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y

    @staticmethod
    def adapter(obj) -> bytes:
        return ('%f;%f' % (obj.x, obj.y)).encode('ascii')

    def converter(self, obj: bytes):
        return Position(*map(float, obj.split(b";")))


Определяем метод adapter, который будет переводить наш тип данных в понятый для Sqlite.

По умолчанию adapter выглядит так.

@staticmethod
def adapter(obj) -> bytes:
    return str(obj).encode('ascii')

Параметр obj — объект нашего типа данных.
В нашем случае — объект класса Position.

class Position(CustomType):
    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y

    @staticmethod
    def adapter(obj) -> bytes:
        return ('%f;%f' % (obj.x, obj.y)).encode('ascii')

    def converter(self, obj: bytes):
        return Position(*map(float, obj.split(b";")))

Определяем метод converter, который будет переводить то, что находилось в базе данных, в наш тип данных.

  • По умолчанию converter не определён. Его необходимо определить самостоятельно.
  • Метод должен возвращать объект нашего класса.

Параметр obj — то же самое, что возвращает метод adapter.

class Position(CustomType):
    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y

    @staticmethod
    def adapter(obj) -> bytes:
        return ('%f;%f' % (obj.x, obj.y)).encode('ascii')

    def converter(self, obj: bytes):
        return Position(*map(float, obj.split(b";")))

Ещё один пример

Создадим тип данных, который будет хранить числа с плавающий точкой(float), который почему-то не был реализован в v2.0.0.

class Float(CustomType, float):
    def converter(self, obj: bytes):
        return Float(obj)
  • Здесь мы не определяем метод __init__, так как наш тип данных наследуется от float.
  • Метод adapter мы не определяем, так как его состояние по умолчанию подходит под наши цели.

Модификация класса Points

Мы не зря писали новый тип данных Position. Он поможет нам хранить координаты точек в таблице Points.

Теперь наш код выглядит так

from sqlite3_api.field_types import CustomType
from sqlite3_api import Table


class Position(CustomType):
    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y

    @staticmethod
    def adapter(obj) -> bytes:
        return ('%f;%f' % (obj.x, obj.y)).encode('ascii')

    def converter(self, obj: bytes):
        return Position(*map(float, obj.split(b";")))


class Points(Table):
    position: Position
    color: str
    size: int

Значения по умолчанию

Допустим мы пишем игру и нам необходимо хранить данные об игроках.
Опишем таблицу Players, которая будет хранить их данные.

from sqlite3_api import Table
from sqlite3_api.field_types import List


class Players(Table):
    nick: str
    gender: str
    lvl: int
    hp: int
    score: int
    items: List

В таком случае, при регистрации новых игроков, мы должны будем указывать значение каждого поля. (ведь мы не можем оставить их пустыми) (может быть расписать 6 значений не так сложно, но представим что их намного больше).
Именно в таких случаях нам помогут значения по умолчанию.

Вот как будет выглядеть код

class Players(Table):
    nick: str
    gender: str
    lvl: int = 1
    hp: int = 100
    score: int = 0
    items: List = List([])

Теперь при регистрации игроков, нам нужно будет указать всего лишь nick и gender.

Предупреждение

При обозначении полей по умолчанию необходимо указывать значения с тем же типом данных!
Обратимся к полю items из таблицы Players. Значением по умолчанию для этого поля мы указали List([]).

Модификация класса Points №2

Укажем значения по умолчанию для некоторых полей нашей таблицы.
Тогда наш код станет таким

from sqlite3_api.field_types import CustomType
from sqlite3_api import Table


class Position(CustomType):
    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y

    @staticmethod
    def adapter(obj) -> bytes:
        return ('%f;%f' % (obj.x, obj.y)).encode('ascii')

    def converter(self, obj: bytes):
        return Position(*map(float, obj.split(b";")))


class Points(Table):
    position: Position
    color: str = 'black'
    size: int = 1

Примечание

Если бы мы хотели указать значение по умолчанию для поля position.
Мы бы сделали так:

position: Position = Position(x=0, y=0)


Наше описание таблицы готово! Можем переходить к работе с ней!