On 12/24/14 13:30, 'Petros Moisiadis' via Django users wrote:
> On 12/23/14 19:13, 'Petros Moisiadis' via Django users wrote:
>> Hello people :)
>>
>> I am struggling with optimizing an admin with inlines which causes too
>> many database requests.
>>
>> My model structure is like this:
>>
>>     class ExampleA(models.Model):
>>         ...
>>    
>>     class ExampleB(models.Model):
>>         aexample = models.ForeignKey('ExampleA', related_name='bexamples')
>>         cexample = models.ForeignKey('ExampleC')
>>         dexample = models.ForeignKey('ExampleD')
>>         eexample = models.ForeignKey('ExampleE')
>>         ...
>>
>>     class ExampleC(models.Model):
>>         ...
>>    
>>     class ExampleD(models.Model):
>>         ...
>>    
>>     class ExampleE(models.Model):
>>         ...
>>
>> The admin classes:
>>
>>     class ExampleBInline(admin.StackedInline):
>>         model = ExampleB
>>         extra = 0
>>
>>     class ExampleAAdmin(admin.ModelAdmin):
>>         inlines = [ExampleBInline]
>>
>>     admin.site.register(ExampleA, ExampleAAdmin)
>>
>> As I can see with django-debug-toolbar, when rendering the admin
>> template for the inline formset with the forms for ExampleB objects, a
>> new db request is sent to db server for each related field of each
>> ExampleB object. Particularly, I am seeing a lot of queries like these:
>>
>>     SELECT ••• FROM `examplec` WHERE `examplec`.`id` = 1 LIMIT 21
>>     SELECT ••• FROM `examplee` WHERE `examplee`.`id` = 2 LIMIT 21
>>     SELECT ••• FROM `examplec` WHERE `examplec`.`id` = 2 LIMIT 21
>>     SELECT ••• FROM `exampled` WHERE `exampled`.`id` = 2 LIMIT 21
>>     SELECT ••• FROM `examplee` WHERE `examplee`.`id` = 3 LIMIT 21
>>
>> The template context is this (I am using grappelli):
>>    
>>                     21        {% if field.is_readonly %}
>>                     22            <div class="grp-readonly">{{
>> field.contents|linebreaksbr }}</div>
>>                     23        {% else %}
>> the marked line =>  24            {{ field.field }}
>>                     25        {% endif %}
>>                     26    {% endif %}
>>                     27        {% if line.fields|length_is:'1' %}{{
>> line.errors }}{% endif %}
>>
>>
>> I have tried the following optimizations:
>>
>> First try:
>>
>>     class ExampleAAdmin(admin.ModelAdmin):
>>         inlines = [ExampleBInline]
>>
>>         def get_queryset(self, request):
>>             qs = super(ExampleAAdmin, self).get_queryset(request)
>>             return qs.prefetch_related('bexamples',
>> 'bexamples__cexample', 'bexamples__dexample', 'bexamples__example')
>>
>> Second try:
>>
>>     class ExampleBInline(admin.StackedInline):
>>         model = ExampleB
>>         extra = 0
>>       
>>         def get_queryset(self, request):
>>             qs = super(ExampleInline, self).get_queryset(request)
>>             return qs.select_related('cexample', 'dexample', 'eexample')
>>
>> Third try:
>>
>>     class BaseExampleBFormSet(BaseInlineFormSet):
>>         def __init__(self, *args, **kwargs):
>>             super(BaseExampleBFormSet, self).__init__(*args, **kwargs)
>>             qs = self.queryset
>>             self.queryset = qs.select_related('cexample', 'dexample',
>> 'eexample')
>>
>>     ExampleBFormSet = inlineformset_factory(ExampleA, ExampleB,
>> formset=BaseExampleBFormSet)
>>
>>     class ExampleBInline(admin.StackedInline):
>>         model = ExampleB
>>         extra = 0
>>         formset = ExampleBFormSet
>>
>> Unfortunately, none of the above works.
>>
>> So, I would be really grateful if anyone could help on this by giving
>> any hint or pointing out what could be possibly missing. Or, could I
>> have hit a restriction of django admin's internals?
>>
>> Thank you in advance,
>>
>> Petros
>>
> Hello again,
>
> I would like to clarify that the big number of db requests is not caused
> by fetching all the objects for the related model to populace select
> boxes for the related fields in the line, as it is often the case. To
> avoid that, I have included the related fields in raw_id_fields. I have
> also used grappelli's convenient autocomplete lookup feature, but that
> does not add extra queries. So, the inline class actually looks like this:
>
>     class ExampleBInline(admin.StackedInline):
>         model = ExampleB
>         extra = 0
>       raw_id_fields = ['cexample', 'dexample', 'eexample']
>       autocomplete_lookup_fields = {
>             'fk': ['cexample', 'dexample', 'example'],
>       }
>
> The only optimization that works is adding the related fields in
> readonly_fields in combination with a queryset changing method with
> select_related(), like this:
>
>     class ExampleBInline(admin.StackedInline):
>         model = ExampleB
>         extra = 0
>       raw_id_fields = ['cexample', 'dexample', 'eexample']
>       autocomplete_lookup_fields = {
>             'fk': ['cexample', 'dexample', 'eexample'],
>       }
>       readonly_fields = ['cexample', 'dexample', 'eexample']
>
>       def get_queryset(self, request):
>             qs = super(ExampleBInline, self).get_queryset(request)
>             return qs.select_related('cexample', 'dexample', 'eexample')
>
>
> However, I am not satisfied with that solution because I do want to be
> able to edit the related fields inline.
>

So the question merely is why the inline class right above produces so
many queries if the 'readonly_fields' line is commented out?
For my data, according to debug toolbar, the view causes 11 queries with
readonly_fields and 115 queries without readonly_fields.

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/549AA8C4.5040309%40yahoo.gr.
For more options, visit https://groups.google.com/d/optout.

Reply via email to