How do I increase an IntegerField in Django?

Viewed 2812

I am making a Todo list web app in Django. I am just learning Django and a very much novice, so any help is greatly appreciated. My problem:

My app will allow users to sign up and they can have a profile of their own. They can create ToDos and delete them as they want. Now, I want to introduce an attribute to all the users called "todos". This is basically an integer value that will keep track of how many todos they have created since they signed up. And every time the user adds a new task, I want this value to increase by 1. I just can't seem to figure out how to implement this.

This is my models.py

from django.db import models
from django.contrib.auth.models import User
from PIL import Image

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    image = models.ImageField(default="default.jpg", upload_to="profile_pics")
    todos = models.IntegerField(default=0)

    def __str__(self):
        return f"{self.user.username} Profile"


    def save(self):
        super().save()

        img = Image.open(self.image.path)

        if img.height > 300 or img.width > 300:
            output_size = (300, 300)
            img.thumbnail(output_size)
            img.save(self.image.path)

views.py

class TodoListView(ListView):
    model = ToDo
    template_name = "ToDo/home.html"
    context_object_name = "todos"
    ordering = ["-date_posted"]


class TodoCreateView(CreateView):
    model = ToDo
    fields = ["title"]
    success_url = reverse_lazy("todo-home")

    def form_valid(self, form):
        form.instance.creator = self.request.user
        user = User.objects.get(username=self.request.user.username)
        user.profile.todos += 1
        return super().form_valid(form)

In the form_valid method, I have tried to increment that value, but this doesn't seem to work. Since I have access to the Admin Panel I can see that when adding a new task, the todos count does not increase.

I am looking for a method that can increment this value and I can call it conveniently when required. Additionally, it would be really helpful if someone could show how to get this todos count in a template so that I can use this value in the Html. Thanks.

2 Answers

You are missing the save method within the form_valid method

class TodoListView(ListView):
    model = ToDo
    template_name = "ToDo/home.html"
    context_object_name = "todos"
    ordering = ["-date_posted"]


class TodoCreateView(CreateView):
    model = ToDo
    fields = ["title"]
    success_url = reverse_lazy("todo-home")

    def form_valid(self, form):
        form.instance.creator = self.request.user
        user = User.objects.get(username=self.request.user.username)
        user.profile.todos += 1
        user.profile.save()
        return super().form_valid(form)

If you wish to access these from within the templates you can just use user.profile.todos directly. E.G. {{ user.profile.todos }} or {% if user.profile.todos > 1 %}More than one{% endif %}

I guess if you add user.save() it will solve part of your problem

user.profile.todos += 1
user.save()

But i recommend you to refactor your code adding Profile foreign_key for ToDo model, then you can get count with ToDo.models.filter(profile__user = myuser).count() and this will give you correct number if you delete ToDo object too. In addition it give you opportunity to filter ToDo list for specific user.

Also you can make calculated field and call it when you need.

class Profile(models.Model)
    ###

    get_todo_count(self):
        return ToDo.models.filter(profile = self).count()
Related