Django适配器CSV需要数小时才能导入

2024-04-29 11:15:35 发布

您现在位置:Python中文网/ 问答频道 /正文

我用Django adaptors上传一个简单的CSV。当我导入100或200个联系人时,它似乎工作得很好。但是当我试图上传一个165kb的文件,有5000个联系人时,它始终没有完成。我让它继续努力,当我一小时后回来时,它还在努力。在

这怎么了?使用Django adaptors导入一个165kb文件不可能需要一个小时以上。代码有问题吗?

 def process(self):
        self.date_start_processing = timezone.now()
        try:


            # Try and import CSV
            ContactCSVModel.import_data(data=self.filepath, extra_fields=[
                {'value': self.group_id, 'position': 5},
                {'value': self.uploaded_by.id, 'position': 6}])

            self._mark_processed(self.num_records)
        except Exception as e:
            self._mark_failed(unicode(e))

csv模型

^{pr2}$

Tags: 文件csvdjango代码importselfiddata
3条回答

我会首先检查csv中没有数据错误。例如,如果一个列有错误的转义字符或不正确的数据类型-也许数据库不能接受某些列上的空值。在

当它挂起时,你能手动检查数据库是否正在填充吗?是通过命令行MySQL提示符还是workbench?如果是,则自动提交被打开,您应该能够看到它挂在哪一行上,然后在CSV中检查该记录。在

但是,如果auto commit被关闭(我不知道Django在默认情况下做了什么,或者您的数据库是如何配置的),那么可能是事务缓冲区溢出了。应该有一种方法可以分阶段手动刷新/提交事务来解决这个问题。在

把你的大任务分成小块。在

第1步-读取CSV文件

两者兼而有之ContactCSVModel.import_from_文件名()和ContactCSVModel.import_from_文件()返回csv行。禁用与django模型的交互以跳过与数据库的交互。这将大大加快任务的速度并打印导入的数据。这肯定有用!在

CSV模型

class ContactCSVModel(CsvModel):

    first_name = CharField()
    last_name = CharField()
    company = CharField()
    mobile = CharField()
    group = DjangoModelField(Group)
    contact_owner = DjangoModelField(User)


    class Meta:
        delimiter = "^"

你的代码

^{pr2}$

第2步-启用django模型交互,但禁用检查数据库中的现有项。

禁用它,因为启用此功能将根据您的自然键规范(我已经阅读了源代码)查询CSV中每一行的DB,以检查现有项。也许你知道CSV中的所有行都是唯一的联系人。在

如果您的问题是整个导入过程中的数据库查询速度慢,这将有所帮助,但如果导入消耗了太多内存,则不会有真正的帮助。在

class ContactCSVModel(CsvModel):

    first_name = CharField()
    last_name = CharField()
    company = CharField()
    mobile = CharField()
    group = DjangoModelField(Group)
    contact_owner = DjangoModelField(User)


    class Meta:
        delimiter = "^"
        dbModel = Contact

第3步-导入大小相等的CSV块

使用CSVModel并启用与联系人模型的交互,但为ContactCSVModel.import_数据(). 我把它设为500。根据你的需要改变它。下面的代码示例(link)是为了让您明白这一点。您需要对其进行一些更改,以便将其放入现有代码中。如果这是内存消耗问题的话。在

import csv
reader = csv.reader(open(self.filepath, 'rb'))

def gen_chunks(reader, chunksize=100):
    """ 
    Chunk generator. Take a CSV `reader` and yield
    `chunksize` sized slices. 
    """
    chunk = []
    for i, line in enumerate(reader):
        if (i % chunksize == 0 and i > 0):
            yield chunk
            del chunk[:]
        chunk.append(line)
    yield chunk

for chunk in gen_chunks(reader, chunksize=500):
    ContactCSVModel.import_data(data=chunk, extra_fields=[
                {'value': self.group_id, 'position': 5},
                {'value': self.uploaded_by.id, 'position': 6}])

第4步-针对大内存消耗和慢操作

由于django适配器在导入期间将所有联系人模型实例保存在内存中,并且由于多个单次提交而不是大容量插入操作,django适配器的操作速度较慢,因此它不太适合较大的文件。在

你有点依赖django适配器。如果依赖这个django包,就不能切换到批量插入。使用top或htop在linux下使用task manager检查内存消耗。如果进程消耗太多,并且操作系统开始交换,那么切换到另一个django插件,可以选择使用更高效的内存消耗和大容量插入,其中有很多用于csv导入。在

另一个提示是使用csv模块进行读取,并使用django模型知识与数据库交互。这对你来说并不是一个真正的挑战-只要试着把你的大局中的一些孤立的任务放在一起,如果它们正在工作的话-祝你好运。在

首先尝试将iterable传递给import_data函数:

ContactCSVModel.import_data(open(self.filepath), extra_fields=[
                {'value': self.group_id, 'position': 5},
                {'value': self.uploaded_by.id, 'position': 6}])

第二件事是使用import_from_filename

^{pr2}$

如果这没用,试着弄清楚它挂在哪里。您可以通过减小csv文件的大小来手动执行此操作,或者您可以在csv.reader上放置一个模拟,或者您可以模拟CsvImporter.process_line,而不是处理行,而是打印出来看看它在哪里停止。如果你需要嘲笑的帮助,请告诉我。在

另外,这个issue也可能是相关的。在

相关问题 更多 >