【问题标题】:How to write a Pandas Dataframe to Django model如何将 Pandas 数据框写入 Django 模型
【发布时间】:2016-03-29 07:03:24
【问题描述】:

我一直在 python 中使用 pandas,我通常将一个数据帧写入我的数据库表,如下所示。我现在正在迁移到 Django,如何通过名为 MyModel 的模型将相同的数据帧写入表?非常感谢您的帮助。

# Original pandas code
    engine = create_engine('postgresql://myuser:mypassword@localhost:5432/mydb', echo=False)
    mydataframe.to_sql('mytable', engine,if_exists='append',index=True)

【问题讨论】:

    标签: python django postgresql pandas dataframe


    【解决方案1】:

    我现在正在做同样的练习。我采用的方法是从 DataFrame 创建一个新对象列表,然后 bulk create 它们:

    bulk_create(objs, batch_size=None)

    该方法以高效的方式将提供的对象列表插入到数据库中(一般只有1个查询,不管有多少对象)

    一个示例可能如下所示:

    # Not able to iterate directly over the DataFrame
    df_records = df.to_dict('records')
    
    model_instances = [MyModel(
        field_1=record['field_1'],
        field_2=record['field_2'],
    ) for record in df_records]
    
    MyModel.objects.bulk_create(model_instances)
    

    【讨论】:

    • 注意限制,例如:"如果模型的主键是 AutoField,它不会像 save() 那样检索和设置主键属性,除非数据库后端支持它(目前是 PostgreSQL)。"
    【解决方案2】:

    在映射到同一个 SQL 表的 Django 模型旁边使用您自己的 pandas 代码

    我不知道有任何明确支持将 pandas 数据帧写入 Django 模型。但是,在 Django 应用程序中,除了使用 ORM(例如通过您的 Django 模型)之外,您仍然可以使用自己的代码来读取或写入数据库

    鉴于您很可能在以前由 pandas 的 to_sql 编写的数据库中有数据,您可以继续使用相同的数据库和相同的 pandas 代码,只需创建一个 Django model that can access that table

    例如如果你的 pandas 代码正在写入 SQL 表 mytable,只需创建一个这样的模型:

    class MyModel(Model):
        class Meta:
            db_table = 'mytable' # This tells Django where the SQL table is
            managed = False # Use this if table already exists
                            # and doesn't need to be managed by Django
    
        field_1 = ...
        field_2 = ...
    

    现在您可以在 Django 中将此模型与您现有的 pandas 代码同时使用(可能在单个 Django 应用中)

    Django 数据库设置

    要在 pandas SQL 函数中获取相同的数据库凭据,只需从 Django 设置中读取字段,例如:

    from django.conf import settings
    
    user = settings.DATABASES['default']['USER']
    password = settings.DATABASES['default']['PASSWORD']
    database_name = settings.DATABASES['default']['NAME']
    # host = settings.DATABASES['default']['HOST']
    # port = settings.DATABASES['default']['PORT']
    
    database_url = 'postgresql://{user}:{password}@localhost:5432/{database_name}'.format(
        user=user,
        password=password,
        database_name=database_name,
    )
    
    engine = create_engine(database_url, echo=False)
    

    不推荐使用替代方法,因为它效率低下

    除了逐行读取数据帧然后创建模型实例并保存它之外,我真的没有看到其他方法,这真的很慢。您可能会摆脱一些批量插入操作,但既然 pandas 的 to_sql 已经为我们做了这件事,为什么还要麻烦呢。将 Django 查询集读入 pandas 数据帧只是效率低下,而 pandas 也能为我们更快地做到这一点。

    # Doing it like this is slow
    for index, row in df.iterrows():
         model = MyModel()
         model.field_1 = row['field_1']
         model.save()
    

    【讨论】:

    • 谢谢 Bakkal,是的,我一直在 python 中直接通过 Qt 使用 pandas。我被困在 create_engine() 值的设置上。我将尝试设置从设置文件中选择的值。
    • 太棒了!正是我需要的!非常感谢!
    • 我觉得有错别字,database+name,应该是database_name
    【解决方案3】:

    我的解决方案使用 pickle 和可选的 zlib 进行压缩

    import pickle
    #optional
    #import zlib
    
    class SuperModel(models.Model):
        DFToStore = models.BinaryField(default=None, null=True, blank=True)
    
        def save(self, *args, **kwargs):
            if not isinstance(self.DFToStore, (bytes)):
                self.DFToStore = pickle.dumps(self.DFToStore)
                #optional with compression
                #self.DFToStore = zlib.compress(pickle.dumps(self.DFToStore))
            super(SuperModel, self).save(*args, **kwargs)
    
        def get_DFToStore(self):
            if isinstance(self.DFToStore, (bytes)):
                return pickle.loads(self.DFToStore)
                #optional with compression
                #return pickle.loads(zlib.decompress(self.DFToStore))
            if not isinstance(self.DFToStore, (bytes)):
                return self.DFToStore
    
    
     
    

    【讨论】:

      猜你喜欢
      • 2017-05-21
      • 1970-01-01
      • 2020-04-11
      • 2018-04-20
      • 2017-02-17
      • 1970-01-01
      • 2019-07-25
      • 1970-01-01
      • 2016-10-06
      相关资源
      最近更新 更多