从CSV导入映射Python SQLAlchemy中的类列标题

从CSV导入映射Python SQLAlchemy中的类列标题,python,sqlite,csv,sqlalchemy,Python,Sqlite,Csv,Sqlalchemy,我在类中设置列名,如下所示: 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(VARC

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

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文件在列名中不使用下划线。它是从internet下载的csv文件。例如,当我导入列名时,像“Date_和_Time”这样的标题被导入为“Date和Time”

我曾假设(这是错误的,对吗?)CSV的列名会映射到我设置的类列标题,但事实并非如此,因此查询无法正常运行。我收到的信息如下:

sqlalchemy.exc.OperationalError:(sqlite3.OperationalError)没有这样的错误 列:stat1.Date_和时间[SQL:'选择stat1.id作为stat1_id, stat1.“日期和时间”为“stat1日期和时间”,stat1.“IP地址”为 “stat1\U IP\U地址”等


是否有一种方法可以自动映射这些内容以使查询成功?或者有一种方法可以自动更改CSV的列标题以在列标题中插入下划线以与类中定义的列相匹配?

有几种不同的方法可以实现这一点:

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

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

我认为,在这种情况下,在模型类属性(
Stat1.Date_和_Time
)中使用下划线,而在CSV头(
,“Date and Time”,…
)中不使用下划线会使代码复杂化一点。但是,根据您实现映射代码的方式,您可以将
列设置为使用一个模型属性名称(
Stat1.日期和时间
) 和不同的数据库列名(例如,将
Stat1.Date\u和_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\u csv\u record()
函数,以便它读取并返回模型属性的列值,然后您可以将它们适当地传递给
Stat1()
构造函数

使用SQLAthanor

实现您自己的反序列化解决方案的一个(我认为更容易)替代方案是使用类似于的库(完全公开:我是该库的作者,所以我有点偏见)。使用SQLAthanor,您可以:

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

    from sqlathanor import generate_model_from_csv
    
    Stat1 = generate_model_from_csv('your_csv_file.csv',
                                    'stat1',
                                    primary_key = 'id')
    
    但是,请注意,如果列标题名称不是ANSI SQL标准列名(例如,如果它们包含空格),则可能会产生错误

  • 定义模型,然后从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来创建一个新的
    Stat1
    实例(数据库中的记录)。new\u from\u CSV()

    就是这样!现在,您的
    my_record
    变量将包含CSV记录的对象表示形式,您可以在选择时将其提交到数据库。因为可以通过多种方式构造CSV文件(使用不同的分隔符、包装策略等)有大量的配置参数可以提供给
    .new\u from\u csv()
    ,但您可以在此处找到所有这些参数:

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


  • 希望这有帮助!

    我一定会查看该库。从所有迹象来看,它可能对其他方面也有帮助。我的目标是使用Selenium每天以编程方式下载一次该文件,将其保存到目录中,然后对脚本进行CRON以上载CSV文件以填充数据库。然后通过计算检索我需要的数据因此,我试图尽可能避免手动操作。然而,一旦我第一次正确设置了所有内容,那么随后的尝试可能就不需要操作了。
    # let's assume you have loaded a single CSV record into a variable "csv_record"
    my_record = Stat1.new_from_csv(csv_record)