2011-06-28 7 views
0

J'ai 2 modèles:comptage efficace des objets

Category(models.Model): 
    name = models.CharField(max_length=30) 
    no_of_posts = models.IntegerField(default=0) # a denormalised field to store post count 

Post(models.Model): 
    category = models.ForeignKey(Category) 
    title = models.CharField(max_length=100) 
    desc = models.TextField() 
    user = models.ForeignKey(User) 
    pub_date = models.DateTimeField(null=True, blank=True) 
    first_save = models.BooleanField() 

Depuis que je veux toujours montrer le pas. des postes Alongwith chaque catégorie, je compte toujours & les stocker chaque fois qu'un utilisateur crée ou supprime un poste de cette façon:

## inside Post model ## 
    def save(self): 
     if not pub_date and first_save: 
     pub_date = datetime.datetime.now() 
     # counting & saving category posts when a post is 1st published 
     category = self.category 
     super(Post, self).save() 
     category.no_of_posts = Post.objects.filter(category=category).count() 
     category.save() 

    def delete(self): 
     category = self.category 
     super(Post, self).delete() 
     category.no_of_posts = Post.objects.filter(category=category).count() 
     category.save() 
     ........ 

Ma question est de savoir si, au lieu de compter chaque objet, peut-on pas utiliser quelque chose comme:

category.no_of_posts += 1 // in save() # and 
category.no_of_posts -= 1 // in delete() 

Ou y at-il une meilleure solution!

Oh, j'ai raté ça! J'ai mis à jour le modèle de poste pour inclure la relation!

+0

J'utilise le champ 'no_of_posts' pour se débarrasser d'interroger la base de données (compter les objets) chaque fois que je veux lister le non. des messages dans les catégories. Je pense qu'il serait plutôt préférable de stocker les comptes dans la base de données en trouvant les instances appropriées de comptage et de stockage. De cette façon, nous n'avons pas besoin de compter les objets chaque fois qu'une liste est requise. ** Beaucoup moins de charge sur la base de données !! ** – anand

Répondre

1

Oui, une bien meilleure solution:

from django.db.models import Count 

class CategoryManager(models.Manager): 
    def get_query_set(self, *args, **kwargs): 
     qs = super(CategoryManager, self).get_query_set(*args, **kwargs) 
     return qs.annotate(no_of_posts=Count('post')) 

class Category(models.Model): 
    ... 
    objects = CategoryManager() 

Puisque vous ne présentez pas la relation entre Post et catégorie, je devinais de la part Count('posts'). Vous pourriez avoir à jouer avec ça.

Oh, et vous voudrez vous débarrasser du champ no_of_posts du modèle. Ce n'est pas nécessaire avec ça. Ou, vous pouvez simplement changer le nom de l'annotation.

Vous pouvez toujours obtenir le nombre de messages avec category.no_of_posts mais vous faites en sorte que la base de données fasse le travail pour vous.