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.