Reputation: 108
I want to present general statistics about the instances of the class "ModelClass" on a web page for my users. Lets say there are some thousands ModelClass-objects, and that there are a lot of statistics that I need to calculate. I have figured out that I can do this with model managers, and here is a (very) simplified example:
class ModelClassCustomManager(models.Manager):
def get_query_set(self):
return super(ModelClassCustomManager, self).get_query_set().filter(is_complete = True)
class ModelClass(models.Model):
is_complete = models.BooleanField(default = False)
...
objects = models.Manager()
complete_objects = ModelClassCustomManager()
My concern is that this drains a lot of resources if this is calculated when users view the page. I would therefore like to calculate it only when I change or create new ModelClass objects since this is the only time the statistics really change. I guess this can be done by overriding the ModelClass save()-method.
What is the best way to save these results? Should I create another django-model for holding the calculated statistics, or is there another way of storing this information?
EDIT: Thanks to pastylegs for a good answer. Doing it this way, however causes some minor bugs, and I figured I'll explain them here, in case anyone else runs into this issue.
First of all, I incorrectly put the imports in the ModelClass at the top, so I got a circular dependency, which gave some weird results. To save yourself some frustration, put them where pastylegs did. Secondly, in order to overwrite the previous calculations of statistics (and not create a new one every time), just replace
if sender is ModelClass and instance is not Null:
count = ModelClass.objects.all().count()
stat = Stat(name='some_name', value=count).save()
with this:
if sender is ModelClass:
count = Match.objects.all().count()
try:
stat = Stat.objects.get(key="Total")
stat.update(key="Total", value=count) #Update statistic
except:
Stat(key="Total", value=count).save() #Create new
Upvotes: 0
Views: 896
Reputation: 53971
I'd create an app called statistics (or similar) that has a simple model to hold key,value pairs:
class Stat(models.Model):
key = models.CharField(..)
value = models.CharField(...)
then use a signal on your own model to run a function every time a user saves/updates a instance of your model. In models.py:
class ModelClass(models.Model):
...
from django.db.models.signals import post_save
from myapp.signal import updates_stats
post_save.connect(updates_stats, sender=ModelClass)
and then create the receiver function to calculate what ever statistics you need in signals.py
from myapp.models import ModelClass
from stats.models import Stat
def update_stats(sender, instance, signal, *args, **kwargs):
if sender is ModelClass and instance is not Null:
count = ModelClass.objects.all().count()
stat = Stat(name='some_name', value=count).save()
This is a very simple and basic approach and only outlines how you can make use of signals to perform calculations but it is a good start. Ideally you should try to calculate these values outside of the request/response cycle (especially if they are big caculations) as it will hang your server and potentially time out your requests, so you should consider using a queuing/task system like Celery to perform the calculation in the background
Upvotes: 3