Django 'model' object is not iterable

Question:

I have a table which shows me the employees registered. I want to generate a simple HTML page according to their DB which includes their name, id, designation, etc.

To do so, I pass an id to the view so it can get the respective user’s details and show me. Everything works fine until the error occurs object is not iterable. Here is my code below.

report.html

{% if emp_item %}
 {% for some in emp_item %}
    <title> {{ some.employee_name }} Report</title>

    <h3>{{ some.employee_name }}</h3>

    <table style="width:30%" border="4">


        <td>{{some.id}}</td>
        <td>{{some.Annual_leave}} </td>
        <td>{{some.Sick_leave}} </td>
        <td>{{some.allowed}} </td>

        </table>

{% endfor %}

<h2>No User</h2>
{% else %}
{% endif %}

views.py

@staff_member_required  # for admin login required
def report(request, id):
    emp_item = Employee.objects.get(id=id)
    context = {'emp_item': emp_item}
    return render(request, 'projectfiles/report.html', context)

urls.py

    url(r'^(?i)Rejectleaves/$', views.rejected_leave_show,
        name='Reject_show'),  # user leaves

    url(r'^(?i)report/(?P<id>d+)$', views.report,
        name='Report'),  # user Report

models.py

class Employee(models.Model):

    allowed = models.BooleanField(default=True)
    employee_name = models.OneToOneField(User, on_delete = models.CASCADE)
    employee_designation = models.CharField(max_length = 5)
    employee_department = models.CharField(max_length = 5)
    Annual_leave = models.PositiveSmallIntegerField(default=5)
    Sick_leave = models.PositiveSmallIntegerField(default=5)

I want to see each individual user’s data according to the process they have made.

Asked By: Talha Murtaza

||

Answers:

Change Employee.objects.get(id=id) to Employee.objects.filter(id=id)

"filter() will always give you a QuerySet" – it’s iterable

get() – return single object and it’s not iterable

Answered By: GGG205

You are iterating over emp_item as an object list. But it is an object as Employee.objects.get(id=id) returns a single object rather than a queryset.

So what you need to do is remove the for-loop from the template as:

{% if emp_item %}
    <title> {{ emp_item.employee_name }} Report</title>

    <h3>{{ emp_item.employee_name }}</h3>
    ...and so on
{% else %}
<h2>No User</h2>
{% endif %}

But if you use get while querying, there is a higher chance that you can get an exception of DoesNotExist. So it is better if you can use Employee.objects.filter(id=id) to avoid any exceptions.

The {% if emp_item %} in your template is of no use if you are querying using get.

For better use, you can use get while querying and send a message to the template if exception occurs. For example:

def report(request, id):
    try:
        emp_item = Employee.objects.get(id=id)
        return render(request, 'projectfiles/report.html', {'emp_item':emp_item})
    except Employee.DoesNotExist:
        return render(request, 'projectfiles/report.html', {'error': 'No data found.'})

Then in template:

{% if error %}
    {{ error }}
{% else %}
    <title> {{ emp_item.employee_name }} Report</title>
    .... and so on to display other data
{% endif %}
Answered By: Sanip

I got the same error below:

TypeError: ‘Category’ object is not iterable

Because I assigned the object made by get() to category__in as shown below:

                         # Here                     # Here
Product.objects.filter(category__in=Category.objects.get(pk=1))

So, I assigned the queryset made by filter() to category__in as shown below, then the error was solved:

                                                    # Here
Product.objects.filter(category__in=Category.objects.filter(pk=1))

Or, I removed __in from category__in as shown below, then the error was solved:

                       # ↓ "__in" is removed
Product.objects.filter(category=Category.objects.get(pk=1))
Answered By: Kai – Kazuya Ito