Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
708 views
in Technique[技术] by (71.8m points)

python - Django admin inline: select_related

Using Django 1.8 on Python 3.4.1 with models:

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

and the following admin.py:

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


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

Of course, i have a problem with multiply queries to database: i have a query for each item in list and a query for each line. So, having 100 items i get 100 ^ 2 queries. I've solved the problem with queries for each line with Caching queryset choices for ModelChoiceField or ModelMultipleChoiceField in a Django form But i still having problem with str method. I've tried the following:

1) adding prefetch_related to ComingAdmin:

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

2) adding select_related to ComingProductInline:

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

3) Defining custom form for inline and adding select_related to 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) Defining a custom formset:

 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) Different combinations for previous 4 methods

And nothing helps: each call of str for PricedProduct makes Django to perform a query for Product table. All of these methods were mentioned on stackoverflow, but they treated ModelAdmin, and do not help with Inline. What do i miss?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The formset solution does work for me, but with a slightly different approach:

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

The BaseInlineFormSet class filters the queryset for you, and you need to take that filtered queryset and add the prefetch. With your formset implementation (the all() queryset) you get unrelated ComingProduct objects and it probably takes much too long to render. When it's the filtered queryset it renders very quickly.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...