Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django 'model' object is not iterable

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

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 %}

view.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.

like image 238
Talha Murtaza Avatar asked May 30 '19 08:05

Talha Murtaza


2 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

like image 173
GGG205 Avatar answered Nov 13 '22 03:11

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 %}
like image 3
Sanip Avatar answered Nov 13 '22 01:11

Sanip