I have been learning django and django rest from several different courses and have started my own project which will be a forum type web application.
I 4 model classes Category, SubCategory, Thread, and Post. What I want to be able to do is have an attribute for subcategory called num_threads that can be updated when ever a thread is made for the subcategory it is related to. Similarly I will want a thread to have attributes num_posts and num_views. I have been using foreign keys to relate the models. Now I am not sure that I am doing that part correctly. Here is my model.py:
from django.db import models
from django.contrib.auth.models import User
class Category(models.Model):
"""
Category Class:
Main Categories for GRDG Forum
Creation and Deletion will be restricted to site admin
"""
# Attributes
name = models.CharField(max_length=32, unique=True, blank=False)
description = models.TextField(max_length=150, blank=True)
def __str__(self):
return self.name
class SubCategory(models.Model):
"""
SubCategory Class:
SubCategories will be one to many relation with category ie: Multiple subcategories related to one category
Creation and Deletion will be restricted to site admin
GET methods restriction will vary by subcategory
"""
# References
category = models.ForeignKey(Category, on_delete=models.CASCADE)
# Attributes
name = models.CharField(max_length=32, unique=True, blank=False)
description = models.TextField(max_length=150)
num_threads = models.IntegerField(max_length=None, default=0)
def __str__(self):
return self.name
class Thread(models.Model):
"""
Class Thread
Threads will be one to many relation to subcategory ie: Multiple threads related to one subcategory
Creation and Deletion restricted to authorized and authenticated users
GET methods restriction will vary by parent subcategory.
"""
# References
subcategory = models.ForeignKey(SubCategory, on_delete=models.CASCADE)
user = models.ForeignKey(User, models.CASCADE)
# Attributes
title = models.CharField(max_length=32, unique=False, blank=False)
num_views = models.IntegerField(max_length=None, default=0)
num_posts = models.IntegerField(max_length=None, default=0)
locked = models.BooleanField(default=False)
author = models.CharField(max_length=32, blank=False)
def __str__(self):
return self.title
class Post(models.Model):
"""
Class Posts
Posts will be one to many relation to Thread ie: Multiple posts related to one Thread
Creation and Deletion restricted to authorized and authenticated users
"""
# References
thread = models.ForeignKey(Thread, on_delete=models.CASCADE)
user = models.ForeignKey(SubCategory, on_delete=models.CASCADE)
# Attributes
body = models.TextField(max_length=500, blank=False)
author = models.CharField(max_length=32, blank=False)
I have references in the model classes that assign the foreign key. Is there a way to automatically update the a models attribute when ever another object with the foreign key is created. IE: Increased a subcategories num_thread, when a thread with the same foreign key is created.
Looking at other question here I have seen mentions of using custom save methods and after looking at its documentation I am still not sure how it would work.
Please let me know thoughts are other resources I could use.
CodePudding user response:
Please don't store the number of Thread
s (or any other aggregate) in a model. This is a form of data duplication which is often an antipattern: it means that you will need to implement handlers when Thread
s are created, updated (refer to another SubCategory
) or removed. It turns out that keeping these in sync is often a hard problem, even if the two tables are stored in the same database.
You can remove the num_thread
field and use .annotate(…)
[Django-doc] and calculate the number of related Thread
s when necessary with:
from django.db.models import Count
SubCategory.objects.annotate(
num_threads=Count('thread')
)
The SubCategory
s that originate from this queryset will then have an extra attribute .num_threads
that contains the number of related Thread
objects.