In my current Django template I have two models in use, which are defined in my views.py as:
'tasks' : IndividualTask.objects.all(),
'updates' : TaskUpdate.objects.all(),
I have set up signals so that when there is an update to a task, an update is created.
Currently, I iterate through each task, then each of their updates and pull out the relevant updates for each task, as shown below.
{% for task in tasks %}
{% for update in updates %}
{% if task.id == update.task.id %}
{{ update.update }}
{% endif %}
{% endfor %}
{% endfor %}
However, I would like to limit the number of updates I show to three.
I have tried using slice, show below, but this limits all updates to the top 3 of all updates as opposed to the top 3 of each individual task's updates.
{% for task in tasks %}
{% for update in updates|slice:":3" %}
{% if task.id == update.task.id %}
{{ update.update }}
{% endif %}
{% endfor %}
{% endfor %}
Models.py is as below:
class IndividualTask(models.Model):
task = models.CharField(
max_length = 256,
blank=False,
null=True,
)
task_description = models.CharField(
max_length = 256,
blank=False,
null=True,
)
expected_completion = models.DateField(
max_length = 64,
null=True,
)
goal = models.ForeignKey(
IndividualGoal,
on_delete=models.CASCADE,
related_name="goals",
blank=False,
null=True,
)
creator = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name="creator",
blank=False,
null=True,
)
owner = models.ForeignKey(
User,
on_delete=models.CASCADE,
blank=False,
null=True,
)
status_choices = [
("", "Select Current Status"),
("Preparation", "Preparation"),
("Review", "Review"),
("Update", "Update"),
("Finalised", "Finalised"),
]
current_status = models.CharField(
max_length=32,
choices = status_choices,
default = "Select current status",
)
created = models.DateField(
auto_now_add = True,
)
def __str__(self):
return f"{self.task}"
class TaskUpdate(models.Model):
update = models.CharField(
max_length = 5000,
)
task = models.ForeignKey(
IndividualTask,
on_delete=models.CASCADE,
null = True,
)
update_created = models.DateField(
auto_now_add = True,
)
update_time_created = models.TimeField(
auto_now_add = True,
)
author = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name="update_author",
blank=True,
null=True,
)
update_choices = [
("New Task", "New Task"),
("New Commentary", "New Commentary"),
]
update_status = models.CharField(
max_length=32,
choices = update_choices,
null = True,
)
class Meta:
ordering = ["-update_created", "-update_time_created"]
I would be grateful for any advice as to how I can limit the number of updates shown for each task to 3 please?
EDIT:
Full traceback shown below:
Environment:
Request Method: GET
Request URL: http://127.0.0.1:8000/tasks/
Django Version: 4.0.2
Python Version: 3.9.10
Installed Applications:
['tasks.apps.TasksConfig',
'notes',
'accounts',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles']
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']
Template error:
In template /Users/Tom/Desktop/squeasy/tasks/templates/tasks/tasks.html, error at line 69
'RelatedManager' object is not iterable
59 : Expected Completion Date
60 : </div>
61 : <div class = expected_completion>
62 : {{ task.expected_completion }}
63 : </div>
64 : </div>
65 : </div>
66 : <div class = task_sub_header>
67 : Latest updates:
68 : </div>
69 : {% for update in task.taskupdate_set|slice:":3" %}
70 : {% if task.id == update.task.id %}
71 : <div class = individual_update>
72 : {% if update.update_status == "New Task" %}
73 : {{ update.author }} created this task on {{ update.update_created|date:"l jS F" }} at {{ update.update_time_created|time:"H:i" }}
74 : {% elif update.update_status == "New Commentary" %}
75 : {{ update.author }} updated the commentary for {{ update.task }} on {{ update.update_created|date:"l jS F" }} at {{ update.update_time_created|time:"H:i" }}
76 : {% endif %}
77 : </div>
78 : {% endif %}
79 : {% endfor %}
Traceback (most recent call last):
File "/usr/local/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/usr/local/lib/python3.9/site-packages/django/core/handlers/base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/Tom/Desktop/squeasy/tasks/views.py", line 28, in tasks
return render(request, "tasks/tasks.html", context)
File "/usr/local/lib/python3.9/site-packages/django/shortcuts.py", line 19, in render
content = loader.render_to_string(template_name, context, request, using=using)
File "/usr/local/lib/python3.9/site-packages/django/template/loader.py", line 62, in render_to_string
return template.render(context, request)
File "/usr/local/lib/python3.9/site-packages/django/template/backends/django.py", line 61, in render
return self.template.render(context)
File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 176, in render
return self._render(context)
File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 168, in _render
return self.nodelist.render(context)
File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 977, in render
return SafeString(''.join([
File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 978, in <listcomp>
node.render_annotated(context) for node in self
File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 938, in render_annotated
return self.render(context)
File "/usr/local/lib/python3.9/site-packages/django/template/loader_tags.py", line 153, in render
return compiled_parent._render(context)
File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 168, in _render
return self.nodelist.render(context)
File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 977, in render
return SafeString(''.join([
File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 978, in <listcomp>
node.render_annotated(context) for node in self
File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 938, in render_annotated
return self.render(context)
File "/usr/local/lib/python3.9/site-packages/django/template/loader_tags.py", line 65, in render
result = block.nodelist.render(context)
File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 977, in render
return SafeString(''.join([
File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 978, in <listcomp>
node.render_annotated(context) for node in self
File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 938, in render_annotated
return self.render(context)
File "/usr/local/lib/python3.9/site-packages/django/template/defaulttags.py", line 298, in render
return nodelist.render(context)
File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 977, in render
return SafeString(''.join([
File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 978, in <listcomp>
node.render_annotated(context) for node in self
File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 938, in render_annotated
return self.render(context)
File "/usr/local/lib/python3.9/site-packages/django/template/defaulttags.py", line 217, in render
nodelist.append(node.render_annotated(context))
File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 938, in render_annotated
return self.render(context)
File "/usr/local/lib/python3.9/site-packages/django/template/defaulttags.py", line 217, in render
nodelist.append(node.render_annotated(context))
File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 938, in render_annotated
return self.render(context)
File "/usr/local/lib/python3.9/site-packages/django/template/defaulttags.py", line 298, in render
return nodelist.render(context)
File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 977, in render
return SafeString(''.join([
File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 978, in <listcomp>
node.render_annotated(context) for node in self
File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 938, in render_annotated
return self.render(context)
File "/usr/local/lib/python3.9/site-packages/django/template/defaulttags.py", line 173, in render
values = list(values)
Exception Type: TypeError at /tasks/
Exception Value: 'RelatedManager' object is not iterable
CodePudding user response:
In the context you can pass the IndividualTask
s with the TaskUpdate
s ordered in descending order with a Prefetch
object [Django-doc]:
from django.db.models import Prefetch
context = {
'tasks' : IndividualTask.objects.prefetch_related(
Prefetch('taskupdate_set', TaskUpdate.objects.order_by('-update_created', '-update_time_created'))
)
}
then in the template you enumerate over the taskupdate_set
:
{% for task in tasks %} {% for update in task.taskupdate_set.all|slice:":3" %} {{ update.update }} {% endfor %} {%endfor %}
Note: It is normally better to make use of the
settings.AUTH_USER_MODEL
[Django-doc] to refer to the user model, than to use theUser
model [Django-doc] directly. For more information you can see the referencing theUser
model section of the documentation.