SQLAlchemy с классом данных по умолчанию не заполняет базу данных postgres - PullRequest
1 голос
/ 08 апреля 2019

Я использую dataclasses в сочетании с классической парадигмой отображения SQLAlchemy. Когда я определяю dataclass в сочетании со значениями по умолчанию для полей int и str, SQLAlchemy не заполняет поля int и str s, но заполняет поля List и datetime. Например, следующий код:

from dataclasses import dataclass, field
from typing import List
from datetime import datetime
from sqlalchemy import create_engine, MetaData, Table, Column, Integer, String, ARRAY, TIMESTAMP
from sqlalchemy.orm import sessionmaker, mapper

metadata = MetaData()
person_table = \
    Table('people', metadata,
          Column('id', Integer, primary_key=True, autoincrement=True),
          Column('name', String(255)),
          Column('age', Integer),
          Column('hobbies', ARRAY(String)),
          Column('birthday', TIMESTAMP)
          )

@dataclass
class Person:
    id: int = None
    name: str = ''
    age: int = 0
    hobbies: List[str] = field(default_factory=list)
    birthday: datetime = field(default_factory=datetime)

mapper(Person, person_table)

engine = create_engine('postgresql://postgres@localhost:32771/test', echo=True)
metadata.create_all(engine)

session = sessionmaker(bind=engine)()
person = Person(id=None, name='Robby', age=33, hobbies=['golf', 'hiking'], birthday=datetime(1985, 7, 25))
session.add(person)
session.commit()

Это правильно заполняет объект person в памяти, но операция commit создает следующие данные в postgres (столбцы name и age равны null):

 id | name | age |    hobbies    |      birthday       
----+------+-----+---------------+---------------------
  1 |      |     | {golf,hiking} | 1985-07-25 00:00:00

Если я изменю класс Person, чтобы удалить значения по умолчанию из name и age, тогда данные будут правильно заполнены в postgres:

@dataclass
class Person:
    id: int = None
    name: str
    age: int
    hobbies: List[str] = field(default_factory=list)
    birthday: datetime = field(default_factory=datetime)

Обратите внимание, я проверил, что при создании объекта person в версии класса "не по умолчанию" поля name и age правильно заполняются в памяти.

Как использовать классические отображения SQLAlchemy в сочетании с классами данных со значениями по умолчанию?

(Python 3.6, SQLAlchemy 1.2.16, PostgreSQL 11.2)

1 Ответ

0 голосов
/ 08 апреля 2019

Поскольку '' и 0 являются соответственно возвращаемыми значениями по умолчанию функций str() и int(), вы можете использовать следующий код для вставки этих значений по умолчанию:

@dataclass
class Person:
    id: int = None
    name: str = field(default_factory=str)
    age: int = field(default_factory=int)
    hobbies: List[str] = field(default_factory=list)
    birthday: datetime = field(default_factory=datetime)

К сожалению, по какой-то причине использование default параметра функции field() не работает, как мы могли ожидать (это может быть ошибка в dataclasses бэкпорте или неправильное понимание ...). Но вы все равно можете использовать default_factory для указания значений, отличных от '' и 0, используя lambda:

@dataclass
class Person:
    id: int = None
    name: str = field(default_factory=lambda: 'john doe')
    age: int = field(default_factory=lambda: 77)
    hobbies: List[str] = field(default_factory=list)
    birthday: datetime = field(default_factory=datetime)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...