rob*_*phy 6 python postgresql sqlalchemy
我正在dataclasses
与 SQLAlchemy 经典映射范例结合使用。当我为和字段dataclass
定义组合默认值时,SQLAlchemy 不会填充 和,但它会填充和字段。例如下面的代码:int
str
int
str
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()
Run Code Online (Sandbox Code Playgroud)
这会正确填充person
内存中的对象,但该commit
操作会在 postgres 中生成以下数据(name
和age
列是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
在类的“无默认”版本中创建对象时,name
和age
字段会在内存中正确填充。
如何将 SQLAlchemy 经典映射与具有默认值的数据类结合使用?
(Python 3.6、SQLAlchemy 1.2.16、PostgreSQL 11.2)
由于''
和分别是和函数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
来指定与''
和0
using不同的值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)