2011-07-03 3 views
2

J'ai un modèle qui ressemble à ceci:performances Django avec M2M

class ParentObject(models.Model): 
    ... 
    services = models.ManyToManyField(Service) 

class ChildObject(models.Model): 
    parent = models.ForeignKey(ParentObject) 
    services = models.ManyToManyField(Service) 

class Service(models.Model): 
    name = ... 
    description = ... 

Donc, en résumé, un objet a une liste de services rattachés et un objets enfant doit avoir d'autres services rattachés. En taille, chaque parent a une liste de 50 à 60 services et chaque enfant (5 par parent) a une liste de 30 à 40 services. Dans django-admin (en utilisant grappelli btw) j'ai mis Child to inline. Le problème est que la page en admin se charge très dur (3-5 secondes) car Django Admin exécute environ 1200 requêtes (pour obtenir le Service à chaque fois - parfois plusieurs fois) pour me montrer les informations à éditer.

Connaissez-vous des conseils/astuces pour optimiser cela?

Merci d'avance.

Répondre

2

Je n'ai pas joué avec grappelli mais en django-admin standard, je considérerais l'utilisation de: ModelAdmin.raw_id_fields. La limite est que vous ne sélectionnez pas les services en utilisant le nom, mais en utilisant pk.

Par défaut, l'administration de Django utilise une interface de sélection -box() pour champs qui sont ForeignKey. Parfois, vous ne voulez pas engager la surcharge de devoir sélectionner toutes les instances à afficher dans la liste déroulante.

raw_id_fields est une liste de champs que vous souhaitez modifier dans une entrée widget de soit pour un ForeignKey ou ManyToManyField:

class ArticleAdmin(admin.ModelAdmin): 
    raw_id_fields = ("newspaper",) 

approche plus dur serait de remplacer gestionnaire admin Service et ajouter cache de niveau de requête. N'oubliez pas de rendre ce gestionnaire disponible en cas d'accès aux objets exaltés.

+0

cette approche offrait une amélioration significative des performances pour une situation très similaire à celle de rsavu. Nous combinons cette approche avec l'utilisation de la mise en cache et de l'invalidation automatique des instances de modèles via [django-cache-machine] (http://jbalogh.me/2010/02/09/cache-machine/) – Archie1986

+0

@ Archie1986 savez-vous si django -cache-machine est entièrement compatible avec django 1.3? Je pourrais devoir l'utiliser bientôt. – Munhitsu

+0

Nous l'utilisons avec Django 1.3 et nous n'avons rencontré aucun problème technique pour le moment. Il convient également de noter que certaines subtilités doivent être prises en compte pour que django-cache-machine ne soit pas plug-and-play (par exemple re: cache invalididation) donc lisez attentivement la documentation. – Archie1986

1

Vous devez remplacer la méthode queryset admin et ajouter un select_related dedans, mettez ceci dans votre fichier admin.py

class ServiceAdmin(admin.ModelAdmin): 
    ... 

    def queryset(self, request): 
     qs = super(ServiceAdmin, self).queryset(request) 
     return qs.select_related() 

admin.site.register(Service, ServiceAdmin) 

Cela seul devrait diminuer vos requêtes un peu, mais le principal problème est que le Django select_related ne suit pas ManyToMany automatiquement. Vous devez faire une solution de rechange supplémentaire pour cela. J'utiliserais le prefill_entry_list de l'application FeinCMS pour faire cela.

Questions connexes