具有数据类的SQLAlchemy默认不填充Postgres数据库 [英] SQLAlchemy with dataclass default not populating postgres database

查看:99
本文介绍了具有数据类的SQLAlchemy默认不填充Postgres数据库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 dataclasses 与SQLAlchemy经典映射范例相结合。当我定义 dataclass 并结合 int str 字段SQLAlchemy不会填充 int str s,但是会填充列出日期时间字段。例如以下代码:

I am using dataclasses combined with the SQLAlchemy classical mapping paradigm. When I define a dataclass combined with default values for the int and str fields SQLAlchemy does not populate the int and strs, but it does populate the List and datetime fields. For example the following code:

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 ):

This correctly populates the person object in memory, but the commit operation produces the following data in postgres (the name and age columns are null):

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

如果我更改 Person 类,从 name age 中删除​​默认值,然后将数据正确填充到postgres:

If I change the Person class to remove the default values from name and age then the data is populated correctly in 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 字段的类的版本。

Note, I have verified that when the person object is created in the "no-default" version of the class that the name and age fields are populated correctly in memory.

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

How do I use SQLAlchemy classical mappings in conjunction with dataclasses with default values?

(Python 3.6,SQLAlchemy 1.2.16,PostgreSQL 11.2)

(Python 3.6, SQLAlchemy 1.2.16, PostgreSQL 11.2)

推荐答案

由于'' 0 分别是默认返回值 str() int()函数,可以使用以下代码插入这些默认值:

Since '' and 0 are respectively default returned values of str() and int() functions, you could use the following code to insert thoses defaults:

@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

Unfortunately, for some reason, using default parameter of field() function does not work as we could expect (could be a bug of the dataclasses backport or a misunterstanding...). But you still can use the default_factory to specify values differents from '' and 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)

这篇关于具有数据类的SQLAlchemy默认不填充Postgres数据库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆