Hey everyone,
I am doing a ToDo app which should look like this:
I have a submit field to add a new list which was never working, not this afternoon and now. The list is below. It is still ‘a work in progress’. Inside of the list I want to have several items linked to the title. The current idea is to create the list with the title and create afterwards the items (perhaps not a good idea…)
This afternoon, I was able to display the title and one list item on the screen from the database but after I realized that I want several list items and not just one, I started to see how to do that. So, I found the ManyToManyField. But I am not able to create anything in the admin panel to display the ToDo List or items on the screen.
models.py:
from django.db import models
class TodoItem(models.Model):
item = models.CharField(max_length=200)
completed = models.BooleanField(default=False)
def __str__(self):
return self.item
class TodoList(models.Model):
title = models.CharField(max_length=200)
items = models.ManyToManyField(TodoItem)
def __str__(self):
return self.title
forms.py:
from django import forms
from .models import TodoList, TodoItem
class TodoListForm(forms.ModelForm):
class Meta:
model = TodoList
fields = ['title', 'items']
class TodoItemForm(forms.ModelForm):
class Meta:
model = TodoItem
fields = ['item', 'completed']
admin.py:
from django.contrib import admin
from .models import TodoList
class TodoListAdmin(admin.ModelAdmin):
filter_horizontal = ('todolist',)
admin.site.register(TodoList)
I am not sure about the filter_horzontal because it was difficult to find information in the docs of Django.
views.py:
from django.shortcuts import render, redirect
from django.contrib import messages
from .models import TodoList, TodoItem
from .forms import TodoListForm, TodoItemForm
def home(request):
if request.method == 'POST':
form = TodoListForm(request.POST or None)
if form.is_valid():
form.save()
todos = TodoList.objects.all()
messages.success(request, ('New Todo List added.'))
return render(request, 'homepage.html', {'todos': todos})
else:
todos = TodoList.objects.all()
return render(request, 'homepage.html', {'todos': todos})
todos = TodoList.objects.all()
return render(request, 'homepage.html', {'todos': todos})
def complete(request, todo_id):
todo = TodoList.objects.get(id=todo_id)
todo.completed = True
todo.save()
return redirect('home')
def incomplete(request, todo_id):
todo = TodoList.objects.get(id=todo_id)
todo.completed = False
todo.save()
return redirect('home')
def edit(request):
return render(request, 'edit.html', {})
homepage.html:
{% extends 'index.html' %}
{% block content %}
<!-- Message component -->
{% if messages %}
{% for message in messages %}
<article class="message is-success">
<div class="message-header">
<p>Nice!</p>
</div>
<div class="message-body">
{{ message }}
</div>
</article>
{% endfor %}
{% endif %}
<!-- End of Message component -->
<!-- Add Todo component -->
<div class="container my-3">
<form method="post">
{% csrf_token %}
<div class="input-group mb-3">
<input name="title" type="text" class="input" placeholder="Name your new Todo List">
<div class="input-group-append">
<button class="btn btn-primary" type="submit">Submit</button>
</div>
</div>
</form>
</div>
<!-- End of Add Todo component -->
<!-- Card component -->
<!-- static values to show the table -->
<div class="container">
<div class="row">
<div class="col-md-6">
<div class="card border-dark bg-light my-3" >
<div class="card-header bg-transparent "> ToDoro App </div>
<div class="card-body">
<div class="card" >
<table class="table table-striped">
<tbody>
<tr>
<td>
<a href="#"><i class="far fa-check-circle"></i></a>
<a href="#"> <i class="far fa-circle"></i> </a>
</td>
<td>
Model has to be fixed
</td>
<td><a href="#"><i class="far fa-edit"></i></a> <a href="#"><i class="far fa-trash-alt"></i></a></td>
</tr>
<tr>
<td>
<a href="#"><i class="far fa-check-circle"></i></a>
<a href="#"> <i class="far fa-circle"></i> </a>
</td>
<td>
Admin has to be fixed
</td>
<td><a href="#"><i class="far fa-edit"></i></a> <a href="#"><i class="far fa-trash-alt"></i></a></td>
</tr>
</tbody>
</table>
</div>
<div class="mt-2">
<a href="#" class="btn btn-danger"> Delete List</a>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- End of static values -->
<div class="container">
{% for todo in todos %}
<div class="row">
<div class="col-md-6">
<div class="card border-dark bg-light my-3" >
<div class="card-header bg-transparent "> {{ todo.title }} </div>
<div class="card-body">
<div class="card" >
<table class="table table-striped">
<tbody>
<tr>
<td>
{% if todo.completed == True %}
<a href="{% url 'complete' todo.id %}"><i class="far fa-check-circle"></i></a>
{% else %}
<a href="{% url 'incomplete' todo.id %}"> <i class="far fa-circle"></i> </a>
{% endif %}
</td>
<td>
{% if todo.completed == True %}
<span style="text-decoration: line-through;"> {{ todo.items }} </span>
{% else %}
{{ todo.items }}
{% endif %}
</td>
<td><a href="{% url 'edit' %}"><i class="far fa-edit"></i></a> <a href="{% url 'edit' %}"><i class="far fa-trash-alt"></i></a></td>
</tr>
</tbody>
</table>
</div>
<div class="mt-2">
<a href="#" class="btn btn-danger"> Delete List</a>
</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
<!-- End of card component -->
{% endblock %}
To be able to display something on the homepage on localhost I used static values.
Admin panel:
Here on the Admin panel I am not able to enter an item that is why I added the filter_horzontal inside of the admin.py file but I can not make it work or because there are no ToDo lists available I can not add any? I have no clue, I am guessing.
While reading again the post I realized that I did a mistake in admin.py:
from django.contrib import admin
from .models import TodoList
class TodoListAdmin(admin.ModelAdmin):
filter_horizontal = ('todolist',)
admin.site.register(TodoListAdmin) # is has to be TodoListAdmin
but I got this error in my terminal:
File "/Users/mac/Desktop/Django/ToDoro/ToDoro/ToDoro_app/admin.py", line 8, in <module>
admin.site.register(TodoListAdmin)
File "/Users/mac/Desktop/Django/ToDoro/venv/lib/python3.9/site-packages/django/contrib/admin/sites.py", line 117, in register
for model in model_or_iterable:
TypeError: 'MediaDefiningClass' object is not iterable
So, I checked again and I changed admin.py:
from django.contrib import admin
from .models import TodoList
class TodoListAdmin(admin.ModelAdmin):
filter_horizontal = ('todolist',)
admin.site.register(TodoList, TodoListAdmin)
stop the terminal and restart the terminal and get error:
raise SystemCheckError(msg)
django.core.management.base.SystemCheckError: SystemCheckError: System check identified some issues:
ERRORS:
<class 'ToDoro_app.admin.TodoListAdmin'>: (admin.E019) The value of 'filter_horizontal[0]' refers to 'todolist', which is not a field of 'ToDoro_app.TodoList'.
System check identified 1 issue (0 silenced).
I can not find the Django docs where I found the example:
class NameAdmin(admin.ModelAdmin):
filter_horizontal = ('category',)
EDIT:
admin.py:
from django.contrib import admin
from .models import TodoList
class TodoListAdmin(admin.ModelAdmin):
filter_horizontal = ('items',)
admin.site.register(TodoList, TodoListAdmin)
now the admin panel display is different but I can not add something:
How can I enter an item?
Sorry for this long text.
Thanks
Doro