【问题标题】:Mapping Class Column Headers in Python SQLAlchemy from CSV import从 CSV 导入映射 Python SQLAlchemy 中的类列标题
【发布时间】:2019-01-18 12:07:01
【问题描述】:

我在类中设置列名,如下所示:

class Stat1(Base):
__tablename__ = 'stat1'
__table_args__ = {'sqlite_autoincrement': True}

id = Column(VARCHAR, primary_key=True, nullable=False)
Date_and_Time = Column(VARCHAR)
IP_Address = Column(VARCHAR)
Visitor_Label = Column(VARCHAR)
Browser = Column(VARCHAR)
Version = Column(VARCHAR)

csv 文件在列名中不使用 UNDERSCORE。它是从 Internet 下载的 csv 文件。例如,当我导入“Date_and_Time”之类的列名标题时,将导入为“Date and Time”。

我曾假设(这是错误的,对吗?)CSV 的列名将映射到我设置的类列标题,但这种情况并没有发生,因此查询无法正常运行。我收到这样的消息:

sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) 没有这样的 列:stat1.Date_and_Time [SQL: 'SELECT stat1.id AS stat1_id, stat1."Date_and_Time" AS "stat1_Date_and_Time", stat1."IP_Address" AS “stat1_IP_Address”……等等

有没有办法自动映射这些以便查询成功?或者一种自动更改 CSV 的列标题以在列标题中插入 UNDERSCORE 以匹配类中定义的列的方法?

【问题讨论】:

    标签: python sqlite csv sqlalchemy


    【解决方案1】:

    有几种不同的方法可以解决这个问题:

    实现您自己的反序列化逻辑

    这意味着读取您的 CSV 文件并将其列映射到您的 Base 模型类的属性的过程是手动完成的(如您的问题中所示),然后您使用自己的自定义代码读取/映射您的 CSV。

    我认为,在这种情况下,在您的模型类属性 (Stat1.Date_and_Time) 中使用下划线,但在 CSV 标头 (...,"Date and Time",...) 中 会使您的代码稍微复杂化。但是,根据您实现映射代码的方式,您可以将您的 Column 设置为使用一个模型属性名称 (Stat1.Date_and_Time) 和一个不同 数据库列名(例如,将Stat1.Date_and_Time 映射到您的数据库列"Date and Time")。为此,您需要传递name 参数,如下所示:

        class Stat1(Base):
    
            __tablename__ = 'stat1'
            __table_args__ = { 'sqlite_autoincrement': True }
    
            id = Column(name = 'id', type_ = VARCHAR, primary_key = True, nullable = False)
            Date_and_Time = Column(name = 'Date and Time', type_ = VARCHAR)
            IP_Address = Column(name = 'IP Address', type_ = VARCHAR)
            # etc.
    

    现在,当您从 CSV 文件中读取记录时,您需要将它们加载到您的 Stat1 类中的适当模型属性中。一个伪代码示例是:

        id, date_and_time, ip_address = read_csv_record(csv_record)
        # Let's assume the "read_csv_record()" function reads your CSV record and returns
        # the appropriate value for `id`, `Date_And_Time`, and `IP_Address`
    
        my_record = Stat1(id = id,
                          Date_And_Time = date_and_time,
                          ip_address
                          # etc.)
    

    这里,诀窍在于实现您的 read_csv_record() 函数,以便它读取并返回模型属性的列值,然后您可以将它们适当地传递给您的 Stat1() 构造函数。

    使用 SQLAthanor

    实现自己的反序列化解决方案的一种(我认为更容易)替代方法是使用像 SQLAthanor 这样的库(完全披露:我是库的作者,所以我是有点偏)。使用 SQLAthanor,您可以:

    1. 以编程方式创建您的 Stat 模型类:

      from sqlathanor import generate_model_from_csv
      
      Stat1 = generate_model_from_csv('your_csv_file.csv',
                                      'stat1',
                                      primary_key = 'id')
      

      但是请注意,如果您的列标题名称不是 ANSI SQL 标准列名称(例如,如果它们包含空格),则可能会产生错误。

    2. 定义您的模型,然后从您的 CSV 创建实例。

      要做到这一点,您将定义您的模型,与上面的操作非常相似:

      from sqlathanor import BaseModel
      
      class Stat1(BaseModel):
      
          __tablename__ = 'stat1'
          __table_args__ = { 'sqlite_autoincrement': True }
      
          id = Column(name = 'id', type_ = VARCHAR, primary_key = True, nullable = False, supports_csv = True, csv_sequence = 1)
          Date_and_Time = Column(name = 'Date and Time', type_ = VARCHAR, supports_csv = True, csv_sequence = 2)
          IP_Address = Column(name = 'IP Address', type_ = VARCHAR, supports_csv = True, csv_sequence = 3)
          # etc.
      

      supports_csv 参数告诉您的 Stat1 类模型属性 Stat1.id 可以从 CSV 反序列化(并序列化为)CSV,csv_sequence 参数表明它始终是CSV 记录。

      现在您可以通过将 CSV 记录传递给 Stat1.new_from_csv() 来创建一个新的 Stat1 实例(数据库中的一条记录):

      # let's assume you have loaded a single CSV record into a variable "csv_record"
      my_record = Stat1.new_from_csv(csv_record)
      

      就是这样!现在您的 my_record 变量将包含您的 CSV 记录的对象表示,然后您可以在选择时将其提交到数据库。由于可以通过多种方式构建 CSV 文件(使用不同的分隔符、包装策略等),因此可以向 .new_from_csv() 提供大量配置参数,但您可以找到所有这些参数这里:https://sqlathanor.readthedocs.io/en/latest/using.html#new-from-csv

      SQLAthanor 是一个非常强大的库,用于将数据移入/移出 CSV 和 SQLAlchemy,因此我强烈建议您查看文档。以下是重要链接:

    希望这会有所帮助!

    【讨论】:

    • 我一定会去看看那个图书馆。从所有迹象来看,它也可能有助于其他事情。我的目标是每天使用 Selenium 以编程方式下载一次文件,将其保存到目录中,然后 CRON 脚本以上传 CSV 文件以填充数据库。然后通过查询计算检索我需要的数据并提供给 Flask。所以我尽量避免手动操作。但是,一旦我第一次正确设置了所有内容,随后的尝试可能不需要任何操作。
    猜你喜欢
    • 2019-06-20
    • 1970-01-01
    • 2018-10-31
    • 2012-06-16
    • 1970-01-01
    • 2018-01-14
    • 1970-01-01
    • 1970-01-01
    • 2020-01-30
    相关资源
    最近更新 更多