I'm using django-filter to show work-hour of employs.
models.py:
...
class Attendance(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="Attendances")
day = models.DateField()
start_time = models.TimeField()
end_time = models.TimeField()
is_confirmed = models.BooleanField()
task = models.ForeignKey(Tasks, on_delete=models.CASCADE)
class Task(models.Model):
title = models.CharField(max_length=255)
project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name="Tasks")
assignee = models.ForeignKey(User, on_delete=models.CASCADE)
...
filter.py:
class WorkhourFilter(django_filters.FilterSet):
user = django_filters.ModelChoiceFilter(queryset=User.objects.filter(is_superuser=False),field_name="user")
project = django_filters.ModelChoiceFilter(queryset=Project.objects.all(), field_name="task__project")
year = django_filters.ChoiceFilter(choices=tuple((x, x) for x in settings.YEARS_LIST),method='year_search')
month = django_filters.ChoiceFilter(choices=tuple((i, x) for i, x in enumerate(settings.MONTH_LIST)),method='month_search' )
class Meta:
model = Attendance
fields = ['user']
def __init__(self, *args, **kwargs):
super(WorkhourFilter, self).__init__(*args, **kwargs)
start_date = ...
end_date = ...
self.queryset = self.Meta.model.objects.filter(user=self.request.user,
day__gte=start_date, day__lte=end_date).values('task__project__title',
'task__project').annotate(
raw_work_hour=Sum(F('end_time') - F('start_time'), ),
confirmed_work_hour=Sum(Case(When(is_verified=1,
then=F('end_time') -
F('start_time'))))).order_by('task__project')
I get 'When' object is not iterable
error.
confirmed_work_hour
has problem but the raw_work_hour
alone is not a problem.
This query is working well in get_queryset()
of corresponding View but when I trying to apply filters it'll break.
trace :
Django Version: 4.2.5
Python Version: 3.9.13
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_extensions',
'crispy_forms',
'crispy_bootstrap5',
'django_tables2',
'django_htmx',
'django_filters',
'ckeditor',
'ckeditor_uploader',
'guardian',
'django_cascading_dropdown_widget',
'dashboard.apps.DashboardsConfig',
'auth.apps.AuthConfig']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django_htmx.middleware.HtmxMiddleware']
Traceback (most recent call last):
File "D:\Python\DjangoTest\venv\lib\site-packages\django\core\handlers\exception.py", line 55, in inner
response = get_response(request)
File "D:\Python\DjangoTest\venv\lib\site-packages\django\core\handlers\base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "D:\Python\DjangoTest\venv\lib\site-packages\django\views\generic\base.py", line 104, in view
return self.dispatch(request, *args, **kwargs)
File "D:\Python\DjangoTest\venv\lib\site-packages\django\contrib\auth\mixins.py", line 73, in dispatch
return super().dispatch(request, *args, **kwargs)
File "D:\Python\DjangoTest\venv\lib\site-packages\braces\views\_access.py", line 438, in dispatch
return super(StaffuserRequiredMixin, self).dispatch(
File "D:\Python\DjangoTest\venv\lib\site-packages\braces\views\_access.py", line 375, in dispatch
return super(GroupRequiredMixin, self).dispatch(
File "D:\Python\DjangoTest\venv\lib\site-packages\django\views\generic\base.py", line 143, in dispatch
return handler(request, *args, **kwargs)
File "D:\Python\DjangoTest\venv\lib\site-packages\django_filters\views.py", line 74, in get
self.filterset = self.get_filterset(filterset_class)
File "D:\Python\DjangoTest\venv\lib\site-packages\django_filters\views.py", line 38, in get_filterset
return filterset_class(**kwargs)
File "D:\Python\DjangoTest\dashboard\filters\workhour_project.py", line 71, in __init__
confirmed_work_hour=Sum(Case(When(is_verified=1, then=F('end_time') - F('start_time')))),
File "D:\Python\DjangoTest\venv\lib\site-packages\sqlparse\sql.py", line 160, in __init__
[setattr(token, 'parent', self) for token in self.tokens]
Exception Type: TypeError at /report/workhour/by_project
Exception Value: 'When' object is not iterable
Thanks to all friends who took the time to solve my problem.
Looking again at the error trace
in the last lines, I noticed a wrong import. Of course, last comment of @willeM_VanOnsem forced me to look at imports again and I am grateful to him.
The Case
command was mistakenly imported from sqlparse.sql
when it should have been imported from django.db.models
.
By applying the above change, the code worked smoothly.
The desired line in the trace that pointed to the sqlparse
package:
File "D:\Python\DjangoTest\venv\lib\site-packages\sqlparse\sql.py", line 160, in __init__
[setattr(token, 'parent', self) for token in self.tokens]