2009-11-07 2 views
0

EDIT: Il se trouve la vraie question est - comment puis-je select_related de suivre les relations m2m je définis? Ce sont ceux qui imposent mon système. Des idées?La réduction des requêtes pour les modèles ManyToMany dans django

J'ai deux classes pour mon application django. Le premier (Item class) décrit un élément ainsi que certaines fonctions qui renvoient des informations sur l'élément. La deuxième classe (classe Itemlist) prend une liste de ces éléments, puis effectue un traitement sur eux pour renvoyer des valeurs différentes. Le problème que je rencontre est que le fait de renvoyer une liste d'éléments depuis Itemlist demande beaucoup de requêtes, et je ne suis pas sûr d'où ils viennent.

class Item(models.Model): 

# for archiving purposes 
archive_id = models.IntegerField() 
users  = models.ManyToManyField(User, through='User_item_rel', 
            related_name='users_set') 

# for many to one relationship (tags) 
tag   = models.ForeignKey(Tag) 
sub_tag  = models.CharField(default='',max_length=40) 

name  = models.CharField(max_length=40) 
purch_date = models.DateField(default=datetime.datetime.now()) 
date_edited = models.DateTimeField(auto_now_add=True) 
price  = models.DecimalField(max_digits=6, decimal_places=2) 
buyer  = models.ManyToManyField(User, through='Buyer_item_rel', 
            related_name='buyers_set') 
comments = models.CharField(default='',max_length=400) 
house_id = models.IntegerField() 

class Meta: 
    ordering = ['-purch_date'] 

def shortDisplayBuyers(self): 
    if len(self.buyer_item_rel_set.all()) != 1: 
     return "multiple buyers" 
    else: 
     return self.buyer_item_rel_set.all()[0].buyer.name 
def listBuyers(self): 
    return self.buyer_item_rel_set.all() 

def listUsers(self): 
    return self.user_item_rel_set.all() 

def tag_name(self): 
    return self.tag 

def sub_tag_name(self): 
    return self.sub_tag 

def __unicode__(self): 
    return self.name 

et la deuxième classe:

class Item_list: 

def __init__(self, list = None, house_id = None, user_id = None, 
      archive_id = None, houseMode = 0): 
    self.list = list 
    self.house_id = house_id 
    self.uid = int(user_id) 
    self.archive_id = archive_id 
    self.gen_balancing_transactions() 
    self.houseMode = houseMode 

def ret_list(self): 
    return self.list 

Donc après je construis avec une grande Liste de produits liste des articles, Itemlist.ret_list() prend jusqu'à 800 requêtes pour 25 articles. Que puis-je faire pour résoudre ce problème?

+0

'len (self.buyer_item_rel_set.all())' changement de useing 'count()'. Ça fait mal (performance). – phoku

Répondre

0

Essayez d'utiliser select_related

Selon une question que je posais here

+0

Donc, si j'ai un ensemble de requêtes qui utilise select_related(), est-ce que le filtrage de ce queryset basé sur les champs liés ne touche pas non plus le db? – victor

+0

Je ne suis pas particulièrement familier avec/les entrailles, mais je crois qu'il va charger et ainsi cache, les objets liés à l'queryset, et exécuter beaucoup moins de requêtes à cause de cela. Bien que, si vous filtrez des objets liés après avoir déjà appelé select_related, je suppose qu'il est logique qu'il devrait re-interroger la base de données. Essayez-le et découvrez-le. –

+0

select_related() ne fonctionne pas avec les champs ManyToMany – Evgeny

0

Dan est raison de vous dire d'utiliser select_related.

select_related peut être lu au sujet here. Ce qu'il fait est retourner dans les mêmes données de requête pour l'objet principal dans votre jeu de requête et le ou les champs spécifiés dans la clause select_related.

Ainsi, au lieu d'une requête comme:

select * from item 

suivi de plusieurs requêtes comme celle-ci à chaque fois que vous accédez à l'un des objets item_list:

select * from item_list where item_id = <one of the items for the query above> 

l'ORM va générer une requête comme:

select item.*, item_list.* 
    from item a join item_list b 
where item a.id = b.item_id 

En d'autres termes: il frappera la base de données une fois pour toutes les données.

+0

select_related ne fonctionne pas avec les champs ManyToMany – Evgeny

0

Vous voulez probablement utiliser prefetch_related

fonctionne de façon similaire à select_related, mais peut traiter des relations selected_related ne peut pas. La jointure se passe en python, mais je l'ai trouvé plus efficace pour ce genre de travail que le grand nombre de requêtes.

Related reading on the subject

Questions connexes