如何将Pandas Dataframe写入现有的Django模型

15

我正在尝试将 Pandas DataFrame 中的数据插入到使用 SQLite 后端的现有 Django 模型Agency中。然而,按照 How to write a Pandas Dataframe to Django modelSaving a Pandas DataFrame to a Django Model 的解答会导致整个 SQLite 表被替换并破坏 Django 代码。具体来说,就是 Django 自动生成的id主键列被index替换,导致在渲染模板时发生错误(no such column: agency.id)。

以下是在 SQLite 表agency上使用 Pandas to_sql 的代码和结果。

models.py中:

class Agency(models.Model):
    name = models.CharField(max_length=128)

myapp/management/commands/populate.py文件中:

class Command(BaseCommand):

def handle(self, *args, **options):

    # Open ModelConnection
    from django.conf import settings
    database_name = settings.DATABASES['default']['NAME']
    database_url = 'sqlite:///{}'.format(database_name)
    engine = create_engine(database_url, echo=False)

    # Insert data data
    agencies = pd.DataFrame({"name": ["Agency 1", "Agency 2", "Agency 3"]})
    agencies.to_sql("agency", con=engine, if_exists="replace")

成功运行 'python manage.py populate' 命令会将三个机构添加到表中:

index    name
0        Agency 1
1        Agency 2
2        Agency 3

然而,这样做已经改变了表的DDL:

CREATE TABLE "agency" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(128) NOT NULL)

致:

CREATE TABLE agency (
  "index" BIGINT, 
  name TEXT
);
CREATE INDEX ix_agency_index ON agency ("index")
如何将DataFrame添加到Django管理的模型中并保持Django ORM不变?
3个回答

13

回答我自己的问题,由于我现在经常使用Pandas将数据导入Django,我犯了一个错误,尝试使用Pandas内置的Sql Alchemy DB ORM,这会修改底层数据库表定义。在上面的环境中,您可以简单地使用Django ORM来连接和插入数据:

from myapp.models import Agency

class Command(BaseCommand):

    def handle(self, *args, **options):

        # Process data with Pandas
        agencies = pd.DataFrame({"name": ["Agency 1", "Agency 2", "Agency 3"]})

        # iterate over DataFrame and create your objects
        for agency in agencies.itertuples():
            agency = Agency.objects.create(name=agency.name)

但是,你可能经常希望使用外部脚本导入数据,而不是像上面那样使用管理命令或使用Django的shell。 在这种情况下,你必须先调用setup方法连接到Django ORM:

import os, sys

import django
import pandas as pd

sys.path.append('../..') # add path to project root dir
os.environ["DJANGO_SETTINGS_MODULE"] = "myproject.settings"

# for more sophisticated setups, if you need to change connection settings (e.g. when using django-environ):
#os.environ["DATABASE_URL"] = "postgres://myuser:mypassword@localhost:54324/mydb"

# Connect to Django ORM
django.setup()

# process data
from myapp.models import Agency
Agency.objects.create(name='MyAgency')
  • 我将我的设置模块myproject.settings导出到DJANGO_SETTINGS_MODULE,以便django.setup()可以获取项目设置。

  • 根据您运行脚本的位置,您可能需要在系统路径中添加路径,以便Django可以找到设置模块。在这种情况下,我在项目根目录下的两个目录中运行我的脚本。

  • 在调用setup之前,您可以修改任何设置。例如,如果您的脚本需要与settings中配置的不同于数据库连接方式进行连接。例如,在针对Django/postgres Docker容器本地运行脚本时。

请注意,上面的示例使用django-environ来指定DB设置。


5

对于那些寻求更高性能和最新解决方案的人,我建议使用manager.bulk_create并实例化Django模型实例,但不要创建它们。

model_instances = [Agency(name=agency.name) for agency in agencies.itertuples()]
Agency.objects.bulk_create(model_instances)

请注意,bulk_create 不会运行信号或自定义保存操作,因此如果您对 Agency 模型有自定义保存逻辑或信号钩子,这些操作将不会被触发。下面是完整的注意事项列表。
文档:https://docs.djangoproject.com/en/3.0/ref/models/querysets/#bulk-create

0
对于仍在寻找答案的人,现在pandas.to_sql()方法有一个名为index_label的附加参数。如果您设置index=True,则还可以为该索引列设置标签。我设置了
df.to_sql('YOUR_TABLE',index=True,index_label='id' ,con=engine, if_exists='replace')

我在我的一个Django项目中测试过,对我有效。 查看文档以获取更多信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接