display data from database

Hello,

I am still working on the ToDoro application. I have decided to not use the inlineformset. Now I am stuck again when displaying the titles with corresponding items on the webpage.

How can I loop through the model and display two or more items with one title? Which condition can I use? I have no idea which condition I should use.

models.py:

class TodoList(models.Model):
	title = models.CharField(max_length=150)

	def __str__(self):
		return self.title


class TodoItem(models.Model):
	item = models.CharField(max_length=200)
	todolist = models.ForeignKey('TodoList', on_delete=models.CASCADE)
	completed = models.BooleanField(default=False)

views.py:

def base(request):
	if request.method == "POST":
		form_list = TodoListForm(request.POST)
		if form_list.is_valid():
			form_list.save()
			return HttpResponseRedirect('/')

	else:
		form_list = TodoListForm()

	if request.method == "POST":
		form_item = TodoItemForm(request.POST)
		if form_item.is_valid():
			form_item.save()
			return HttpResponseRedirect('/')
			
	else:
		form_item = TodoItemForm()

	# grap all TodoItems from database:
	all_todos = TodoItem.objects.all()

	# grap all TodoLists (titles) from database:
	titles = TodoList.objects.all()

	return render(request, 'edit.html', 
		{
		'form_list': form_list, 
		'form_item': form_item,
		'all_todos': all_todos,
		'titles': titles
		})

edit.html:

<div class="container">
  {% for todo in all_todos %}
  <h3>{{ todo.todolist }}</h3>
  <p>{{ todo.item }}</p>
  {% endfor %}
</div>

webpage:

How can I display:

Lorem ipsum dolor

nisi ut aliquip ex ea
incididunt ut labore et

If you need further information please let me know.

Doro

The easiest way to do this would be nested loops. You render the list name, and then render each of the items associated with that name. You can use the prefetch_related function in your TodoList query to retrieve the related TodoItem entries and then in your template iterate over that related set.

Thank you Ken,
that was exactly my idea. I just do not know how I can do that.

I am not able to get the if condition working, that is why I wrote the task.

	for title in titles:
		for item in items:
			if title == (title.id == 3):
				print('here: ', item)
			else:
				print('FAILED')

or:

	for title in titles:
		for item in items:
			if title == title.title:
				print('here: ', item)
			else:
				print('FAILED')

or:

	for title in titles:
		for item in items:
			if title == 'Lorem ipsum dolor':
				print('here: ', item)
			else:
				print('FAILED')

all of these are FAILing.

I can access the titles and the items but I can not get them together to one list.

In the html part I was playing with the same issue around:

views.py:

todolists = TodoList.objects.all()
todoitems = TodoItem.objects.all()

base.html:

<!-- first List Title -->
  {% for todo in todolists %}
    {% if todo.id == 1 %}
      {{ todo.title }}
    {% endif %}
  {% endfor %}

  <hr>
  <hr>
    <!-- second List Title -->
    {% for todo in todolists %}
      {% if todo.id == 1 %}
        {{ todo.title }}
        {% for todoitem in todoitems %}
          {% if todoitem.todolist.id == 1 %}
            {{ todoitem.item }}
          {% endif %}
        {% endfor %}
      {% endif %}
    {% endfor %}

I am able to display the title and all of the items connected to the title but the above code is not dynamic and I do not know how to change it. I just do not get it how I can do it. I can not use if todo.id == 1 and if todo.id == 2 and if todo.id == 3 etc.

And what is the difference between Model.objects.all() and Model.objects.prefetch_related(‘ForeignKeyField’)?

I get the same output in terminal for:

	# grap all TodoItems from database:
	item_list = TodoItem.objects.all()

	# prefetch_related function:
	items = TodoItem.objects.prefetch_related('todolist')
	print('prefetch_related function: ', items)
	print('all function: ', item_list)

terminal: (I manually put space between for visability)

prefetch_related function:  
<QuerySet 
[<TodoItem: nisi ut aliquip ex ea>, 
<TodoItem: incididunt ut labore et>, 
<TodoItem: sed do eiusmod tempor>, 
<TodoItem: consectetur adipiscing elit>]>

all function:  
<QuerySet 
[<TodoItem: nisi ut aliquip ex ea>, 
<TodoItem: incididunt ut labore et>, 
<TodoItem: sed do eiusmod tempor>, 
<TodoItem: consectetur adipiscing elit>]>

Thanks
Doro

There are no “conditions” involved.

It’s one query, not two. You don’t use a separate query for TodoItem.

You want to use the “related object manager” for your inner loop to only iterate over those instances of TodoItem that are related to the current instance of TodoList within the loop.

Also see Following relationships backward

Hello,
Thanks Ken, I learned a lot with this project and with your help. Thank you!

Still I would like to ask this question below. It is the same output but is it the same? Perhaps it is the same in this example.

Doro

What do the docs say is the purpose of prefetch_related?

Django docs 4.1:
“… designed to stop the deluge of database queries that is caused by accessing related objects, …”

What does that mean?
Ok, does that means with Model.objects.prefetch_related('item) I point directly to the items I want to be searched for and with Model.objects.all() I am searching for every related item in the model? I am not sure.

From the previous paragraph:

Returns a QuerySet that will automatically retrieve, in a single batch, related objects for each of the specified lookups.

If you have an instance of TodoList named a_todo_list, then the set of TodoItem related to that instance would be accessed as a_todo_list.todoitem_set.

Without prefetch_related, that causes another query to be issued.

And that means that as you’re iterating over TodoList, you’re executing a query for each element of that list.

This is known as the “N + 1” problem. You’re executing one query for TodoList and an extra query for each element in that list.

The purpose of prefetch_related is to perform one additional query to retrieve all those related items at the same time you’re retrieving the TodoList items. It’s a performance-enhancement facility. If you’ve got 10 items in your TodoList table, it reduces the number of queries being made from 11 to 2.

1 Like