AttributeError: 'list' object has no attribute 'iter_rows'

Question:

I’d read an excel file, there I’m getting all sheets but when doing this
getting that error.

views.py

from Django.shortcuts import render
import openpyxl


def index(request):
    if "GET" == request.method:
        return render(request, 'file/index.html', {})
    else:
        excel_file = request.FILES["excel_file"]

        # you may put validations here to check extension or file size

        wb = openpyxl.load_workbook(excel_file)

        # getting all sheets
        worksheet = wb.sheetnames
        print(worksheet)

        excel_data = list()
        # iterating over the rows and
        # getting value from each cell in row
        for row in worksheet.iter_rows():
            row_data = list()
            for cell in row:
                row_data.append(str(cell.value))
            excel_data.append(row_data)

        return render(request, 'file/index.html', {"excel_data": excel_data})
Asked By: mahesh chougule

||

Answers:

As per documentation, wb.sheetnames returns sheet names which is a list, you need to select a sheet first, then you can use iter_rows. For example:

If you want to use first sheet:

sheet_name = wb.sheetnames[0]
worksheet = wb[sheet_name]
for row in worksheet.iter_rows():
   ...

Or if you want to go through all sheets:

for sheet_name in wb.sheetnames:
    worksheet = wb[sheet_name]
    for row in worksheet.iter_rows():
        # rest of the code

Saving to DB

For saving, you can use a model. Lets say you have a model named WBData, which has fields to match the columns, then you can save it like this:

for row in worksheet.iter_rows():
    row_data = list()
    for cell in row:
        row_data.append(str(cell.value))
    WBData.objects.create(field1=row_data[0], field2=row_data[1],...)
Answered By: ruddra

worksheet = wb.sheetnames actually returns the sheet names as list.

How you can get the sheet:

if 'sheet name' in wb.sheetnames:
    sheet = wb['sheet name']

You can do the following one:

for name in wb.sheetnames:
    sheet = wb[name]
    for row in sheet.iter_rows():
        # Your code

Update (Saving into DB)::
If a sheet corresponds to a model and you want to save data into DB then see the following section:

sheet_to_model = {
    'sheet1':{
        'model': Model1, 
        'column_map': {
            'xl column 1': 'model_field_1',
            'xl column 2': 'model_field_2',
        }
    }

}

# Also map each sheet's column name to your model's field name

for name in wb.sheetnames:
    sheet = wb[name]
    for row in sheet.iter_rows():
        # Here get model name using sheet name and the sheet_to_model dict. 
        # Get each cell value from row and column name and create a dict using  
        # the model's field name and the cell value. Then inset using Model.objects.create(**data)

Update 2 (Saving into DB):
Suppose your xl file has the following sheets and corresponding columns:

  • Sheet1 (Columns: ‘s1c1’, ‘s1c2’, ‘s1c3’)
  • Sheet1 (Columns: ‘s1c1’, ‘s1c2’, ‘s1c3’)

And you have the models maned Model1 and Model2. Data of Sheet1 will be saved into Model and data of Sheet2 into Model2 Now, see the following code to understand how data is stored in corresponding model:

import openpyxl
from django import models


class Model1(models.Model):
    m1f1 = models.IntergerField()
    m1f2 = models.IntergerField()
    m1f3 = models.IntergerField()


class Model2(models.Model):
    m2f1 = models.CharField(max_length=128)
    m2f2 = models.CharField(max_length=128)
    m2f3 = models.CharField(max_length=128)


sheet_to_model = {
    'Sheet1':{
        'model': Model1, 
        'columns': ['s1c1', 's1c2', 's1c3'],
        'column_map': {
            's1c1': 'm1f1',
            's1c2': 'm1f2',
            's1c3': 'm1f3',
        }
    }, 
    'Sheet2':{
        'model': Model2, 
        'columns': ['s2c1', 's2c2', 's2c3'],
        'column_map': {
            's2c1': 'm2f1',
            's2c2': 'm2f2',
            's2c3': 'm2f3',
        }
    }

}

wb = openpyxl.load_workbook('./datas.xlsx')

print(wb.sheetnames)

for sheet_name in wb.sheetnames:
    sheet = wb[sheet_name]
    for index, row in enumerate(sheet.iter_rows()):
        data = {}
        if index: # First row is columns name
            for idx2, col in enumerate(row):
                # print(col.value)
                p = sheet_to_model[sheet_name]['columns'][idx2]
                # print(p)
                data[sheet_to_model[sheet_name]['column_map'][p]] = col.value
            # print(data)
            sheet_to_model[sheet_name]['model'].objects.create(**data)

You can also learn and use Pandas to handle this types of situations more easily.

Answered By: Mahmood Al Rayhan
for name in work_book.sheetnames:
    sheet = work_book[name]
    for row in sheet.iter_rows():
        # Your code
Answered By: SaiKe
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.