2015-04-15 12 views
5

Utilizzando Django 1.8 su Python 3.4.1 con i modelli:Django Admin linea: select_related

class Product(models.Model): 
    name = models.CharField(max_length=255) 
    # some more fields here 

    def __str__(self): 
     return self.name 


class PricedProduct(models.Model): 
    product = models.ForeignKey(Product, related_name='prices') 
    # some more fields here 

    def __str__(self): 
     return str(self.product) 

class Coming(models.Model): 
    # some unimportant fields here 


class ComingProducts(models.Model): 
    coming = models.ForeignKey(Coming) 
    priced_product = models.ForeignKey(PricedProduct) 
    # more unimportant fields 

e la seguente admin.py:

class ComingProductsInline(ForeignKeyCacheMixin, admin.TabularInline): 
    model = ComingProducts 


class ComingAdmin(admin.ModelAdmin): 
    inlines = [ComingProductsInline] 

Naturalmente, ho un problema con le query si moltiplicano al database: ho una query per ogni elemento in elenco e una query per ogni riga. Quindi, avendo 100 elementi ottengo 100^2 query. Ho risolto il problema con le query per ogni riga con Caching queryset choices for ModelChoiceField or ModelMultipleChoiceField in a Django form Ma ho ancora problemi con il metodo str. Ho provato la seguente:

1) aggiungendo prefetch_related a ComingAdmin:

def get_queryset(self, request): 
    return super(ComingAdmin, self).get_queryset(request). \ 
    prefetch_related('products__product') 

2) l'aggiunta di select_related a ComingProductInline:

def get_queryset(self, request): 
    return super(ComingProductsInline, self).get_queryset(request). \ 
    select_related('priced_product__product') 

3) Definizione di modulo personalizzato per la linea e l'aggiunta di select_related field queryset:

class ComingProductsInline(ForeignKeyCacheMixin, admin.TabularInline): 
    model = ComingProducts 
    form = ComingProductsAdminForm 

class ComingProductsAdminForm(ModelForm): 
    def __init__(self, *args, **kwargs): 
       super(ComingProductsAdminForm, self).__init__(args, kwargs) 
       self.fields['priced_product'].queryset = PricedProduct.objects.all(). \ 
       select_related('product') 

    class Meta: 
     model = ComingProducts 
     fields = '__all__' 

4) Definizione di un modulo personalizzato:

class ComingProductsInline(ForeignKeyCacheMixin, admin.TabularInline): 
    model = ComingProducts 
    formset = MyInlineFormset 

class MyInlineFormset(BaseInlineFormSet): 
    def __init__(self, data=None, files=None, instance=None, 
      save_as_new=False, prefix=None, queryset=None, **kwargs): 
     super(MyInlineFormset, self).__init__(data, files, instance, 
              save_as_new, prefix, queryset, **kwargs) 
     self.queryset = ComingProducts.objects.all(). \ 
     prefetch_related('priced_product__product') 

5) diverse combinazioni per precedenti 4 metodi

e niente aiuta: ogni chiamata di str per PricedProduct rende Django per eseguire una query per la tabella Product. Tutti questi metodi sono stati menzionati su StackOverflow, ma hanno trattato ModelAdmin e non aiutano con Inline. Cosa mi manca?

risposta

1

Attualmente sto lavorando su un problema simile. Quello che ho trovato è documentato in questa discussione: Translatable Manytomany fields in admin generate many queries

Un'osservazione importante che ho fatto è che la mia soluzione funziona solo per Django 1.7x e non per 1.8. Esattamente lo stesso codice, con d1.7 ho ordine di 10^1 query, e con la nuova installazione di d1.8 ho 10^4.

soluzione
3

il formset funziona per me, ma con un approccio leggermente diverso:

class MyInlineFormset(BaseInlineFormSet): 
    def __init__(self, *args, **kwargs): 
     super(MyInlineFormset, self).__init__(*args, **kwargs) 
     self.queryset = self.queryset.prefetch_related('priced_product__product') 

classe Il BaseInlineFormSet filtra il set di query per voi, e avete bisogno di prendere quel set di query filtrata e aggiungere il prefetch. Con la tua implementazione di formset (il queryset all() ottieni oggetti ComingProduct non collegati e probabilmente ci vorrà molto tempo per il rendering. Quando è il queryset filtrato, lo rende molto rapidamente.

+0

Oh. questo è un risparmiatore di vita. Avevo un modello A, che aveva molti inline del modello B. B aveva tre m2m e due relazioni fk. inoltre. è stata utilizzata la traduzione del modello. Inoltre, Grappelli con il suo completamento automatico ha aiutato. – Aitvaras

+0

sfortunatamente, non funziona in Django 2.0 – ramusus

+0

In che modo? Non sembra che il codice rilevante di Django sia cambiato – noamk