【问题标题】:Trouble reading CSV into Django models with python DictReader使用 python DictReader 将 CSV 读入 Django 模型时遇到问题
【发布时间】:2014-02-01 13:21:58
【问题描述】:

我正在使用 Cloud9(据我所知,它目前使用 Python 2.6,而不是 Python 3)来编写 Django 应用程序。我正在尝试使用 DictReader 读取 CSV 文件并使用 CSV 中的每一列来创建模型的新实例并填充模型字段。

views.py

class GenerateFromCSV(CreateView):
    model = group
    template_name = "my_app/csv_generate.html"
    def form_valid(self, form):
        new_group = form.save()
        the_csv = open(new_group.group_csv, 'rbU')
        fieldnames = ['c_type', 'f_name', 'q_type', 'ans', 'n_questions', 'bucket']
        data_file = csv.DictReader(the_csv, fieldnames = fieldnames, delimiter=',', dialect=csv.excel)
        for row in data_file:
            new_card = Card(
                name = 'card',
                card_type = row['c_type'], 
                file_name = row['f_name'], 
                question_type = row['q_type'], 
                answer = row['ans'], 
                num_questions = row['n_questions'], 
                bucket = row['bucket'],
                exam = new_exam)
            new_card.save()

models.py

class Group(models.Model):
    name = models.CharField(max_length=255, blank = True)
    subject = models.CharField(max_length=255, choices = SUBJECT, blank = True)
    num_questions = models.IntegerField(default=0, blank = True, null = True)
    group_csv = models.FileField(upload_to='csv', blank = True, null = True)
    def __unicode__(self):
        return self.name

class Card(models.Model):
    name = models.CharField(max_length=255, blank = True)
    #ordered same as column order in CSV
    card_type = models.CharField(max_length=255, choices = CARDTYPE, blank = True)
    file_name = models.CharField(max_length=255, blank = True)
    question_type = models.IntegerField(default = 0, blank = True, null = True)
    answer = models.IntegerField(max_length = 1, choices = ANSWERS, blank = True, null = True)
    num_questions = models.IntegerField(default = 0, blank = True, null = True)
    bucket = models.CharField(max_length=255, blank = True)
    exam = models.ForeignKey(Exam)
    def __unicode__(self):
        return self.name or 'card'

使用上面的代码,当我在 CSV 上调用 open() 时,我得到一个 TypeError(强制转换为 Unicode:需要字符串或缓冲区,找到 FieldFile)。如果我删除对 open() 的调用,我会收到错误消息:“在未引用的字段中看到换行符 - 你需要以通用换行模式打开文件吗?”

我的 CSV 格式为(并非每一列都包含每一行的数据):

3,the_file_name.png,0,"00001",,Equations

正确的语法是什么?

编辑 这是我的堆栈跟踪:

Traceback:
File "/usr/libexec/openshift/cartridges/c9-0.1/root/python2.6.6/site-packages/Django-1.5-py2.6.egg/django/core/handlers/base.py" in get_response
  115.                         response = callback(request, *callback_args, **callback_kwargs)
File "/usr/libexec/openshift/cartridges/c9-0.1/root/python2.6.6/site-packages/Django-1.5-py2.6.egg/django/views/generic/base.py" in view
  68.             return self.dispatch(request, *args, **kwargs)
File "/usr/libexec/openshift/cartridges/c9-0.1/root/python2.6.6/site-packages/Django-1.5-py2.6.egg/django/views/generic/base.py" in dispatch
  86.         return handler(request, *args, **kwargs)
File "/usr/libexec/openshift/cartridges/c9-0.1/root/python2.6.6/site-packages/Django-1.5-py2.6.egg/django/views/generic/edit.py" in post
  199.         return super(BaseCreateView, self).post(request, *args, **kwargs)
File "/usr/libexec/openshift/cartridges/c9-0.1/root/python2.6.6/site-packages/Django-1.5-py2.6.egg/django/views/generic/edit.py" in post
  165.             return self.form_valid(form)
File "/var/lib/stickshift/52a55ef4e0b8cde0ff000036/app-root/data/705411/zamrdjango/zamr/views.py" in form_valid
  35.         with new_exam.exam_csv.open('rbU') as the_csv:

Exception Type: AttributeError at /import/
Exception Value: 'NoneType' object has no attribute '__exit__'

【问题讨论】:

  • new_item = Item( 是什么意思,你的意思是 new_card = Card 吗?
  • 是的,我已将其编辑为正确。

标签: python django csv


【解决方案1】:

好吧,我最终通过在 csv 上调用 .read() 然后调用 .splitlines() 来获取每行的行和列来修复它。这是我的新views.py:

def form_valid(self, form):
    new_group = form.save()
    print(new_exam.exam_csv.name)
    data = new_group.group_csv.read()
    rows = data.splitlines()
    for row in rows:
        columns = row.split(',')
        print(columns)
        new_card = Card(
            name = columns[0],
            card_type = columns[0], 
            file_name = columns[1], 
            question_type = int(columns[2]),
            answer = columns[3].replace('"', '').strip(), 
            num_questions = columns[4], 
            bucket = columns[5],
            group = new_group)
        print(new_card.name)
        new_card.save()

我确定这不是正确的语法或约定,还有一些事情需要弄清楚(例如列名),但现在它正在正确地将所有信息解析到正确的模型字段中。

【讨论】:

    【解决方案2】:

    查看FileField 的文档,因为问题是您没有将文件名传递给文件open 函数:
    https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.fields.files.FieldFile

    您的代码可以改为:

    class GenerateFromCSV(CreateView):
        model = group
        template_name = "my_app/csv_generate.html"
        def form_valid(self, form):
            new_group = form.save()
            with new_group.group_csv.open('rbU') as the_csv:
                fieldnames = ['c_type', 'f_name', 'q_type', 'ans', 'n_questions', 'bucket']
                data_file = csv.DictReader(the_csv, fieldnames = fieldnames, delimiter=',', dialect=csv.excel)
                for row in data_file:
                    new_card = Card(
                        name = 'item',
                        card_type = row['c_type'], 
                        file_name = row['f_name'], 
                        question_type = row['q_type'], 
                        answer = row['ans'], 
                        num_questions = row['n_questions'], 
                        bucket = row['bucket'],
                        exam = new_exam)
                    new_card.save()
    

    【讨论】:

    • 我明白了,我想我误解了 Python with/as 语句。我现在收到属性错误:“NoneType”对象没有属性“exit”。我不确定如何处理这个问题,上下文处理程序是否尝试在 csv 文件上调用 exit 但无法调用?
    • 是的 __exit__the_csv 块末尾的 the_csv 文件对象上被调用...如果 the_csvNone,你应该得到这个错误是很奇怪的,似乎更早会引发另一个异常。你能发布一个完整的堆栈跟踪吗?
    • 好的,我在上面添加了回溯。我还尝试确保每行中的每一列都有数据,以防出现问题,并尝试使用不同的 csv(以防我使用的csv由于某种原因而无效)但我仍然遇到相同的属性错误.
    • 好的,它很早就失败了,所以看起来问题只是你的new_group.group_csv 字段有一个None 值而不是一个文件
    【解决方案3】:

    我做了这样的事情

    {# csv-import.html %}
    <form action="/csv-import" method="POST" enctype="multipart/form-data">
        {% csrf_token %}
        <input type="file" required name="csvfile" id="id_csvfile" />
        <input type="submit" />
    </form>
    
    # views.py
    @login_required
    def CSVImport(request):
        if request.method == "GET":
            logger.info(f"Get /csv-import")
        elif request.method == "POST":
            logger.info(f"POST /csv-import")
            csv_len = 0
            try:
                csv_file = request.FILES["csvfile"]
                if not csv_file.name.endswith('.csv'):
                    messages.error(request,'File is not CSV type')
                    return HttpResponseRedirect(reverse("myapp:upload_csv"))
                #if file is too large, return
                if csv_file.multiple_chunks():
                    messages.error(request, "Uploaded file is too big (%.2f MB)." % (csv_file.size/(1000*1000),))
                    return HttpResponseRedirect(reverse("myapp:upload_csv"))
                file_data = csv.DictReader(csv_file.read().decode('utf-8').splitlines())
                for row in file_data:
                    print('row', row)
                    csv_len += 1
    
            except Exception as e:
                logging.getLogger("error_logger").error("Unable to upload file. "+repr(e))
                messages.error(request,"Unable to upload file. "+repr(e))
            messages.add_message(request, messages.INFO, f"Updated {csv_len} meetings.")
        return render(request, "csv-import.html")
    

    【讨论】:

      猜你喜欢
      • 2015-08-31
      • 2020-01-27
      • 2010-11-15
      • 2019-04-26
      • 2021-11-27
      • 2018-01-06
      • 2011-04-10
      • 1970-01-01
      • 2016-04-06
      相关资源
      最近更新 更多