SQLAlchemy 的数据类默认不填充 postgres 数据库

rob*_*phy 6 python postgresql sqlalchemy

我正在dataclasses与 SQLAlchemy 经典映射范例结合使用。当我为和字段dataclass定义组合默认值时,SQLAlchemy 不会填充 和,但它会填充和字段。例如下面的代码:intstrintstrListdatetime

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()
Run Code Online (Sandbox Code Playgroud)

这会正确填充person内存中的对象,但该commit操作会在 postgres 中生成以下数据(nameage列是null):

 id | name | age |    hobbies    |      birthday       
----+------+-----+---------------+---------------------
  1 |      |     | {golf,hiking} | 1985-07-25 00:00:00
Run Code Online (Sandbox Code Playgroud)

如果我更改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)
Run Code Online (Sandbox Code Playgroud)

请注意,我已经验证,当person在类的“无默认”版本中创建对象时,nameage字段会在内存中正确填充。

如何将 SQLAlchemy 经典映射与具有默认值的数据类结合使用?

(Python 3.6、SQLAlchemy 1.2.16、PostgreSQL 11.2)

Try*_*yph 5

由于''和分别是和函数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)
Run Code Online (Sandbox Code Playgroud)

不幸的是,由于某种原因,使用函数default参数field()并不能像我们预期的那样工作(可能是dataclasses向后移植的错误或误解......)。但您仍然可以使用default_factory来指定与''0using不同的值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)
Run Code Online (Sandbox Code Playgroud)