Hi Petros, I think it's because "value_from_object" only passes the primary key of the object and then raw_id_field re-queries it.
https://github.com/django/django/blob/40ccef16/django/contrib/admin/widgets.py#L195 https://github.com/django/django/blob/40ccef16/django/forms/models.py#L151 https://github.com/django/django/blob/40ccef16/django/db/models/fields/__init__.py#L844-L848 Basically, even if you use select_related(), django still queries your object again. It looks like a spot where there could be some optimization. Collin On Monday, December 29, 2014 1:45:08 PM UTC-5, Ernest0x wrote: > > Hello Collin, > > On 12/29/14 07:25, Collin Anderson wrote: > > Hi Petros, > > I think the raw_id_fields still display the __str__/__unicode__ of the > selected object so therefore need to get queried. I wonder if > select_related would possibly help? > > > I do have select_related in the queryset (look at the last version of > ExampleBInline in my previous post). > > The thing is that if the same fields that are included in raw_id_fields > are also included in readonly_fields, the queries are reduced dramatically, > despite the fact that the same amount of information is displayed in both > cases. __str__()/__unicode__ is still called when the fields are in > readonly_fields, so it is really very strange why there is difference > between adding and commenting out the readonly_fields line. > > Very strange... > > Collin > > On Wednesday, December 24, 2014 5:53:02 AM UTC-6, Ernest0x wrote: >> >> 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] <javascript:>. > To post to this group, send email to [email protected] > <javascript:>. > 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/778f1f33-3c34-491e-a062-9527ec703bfd%40googlegroups.com > > <https://groups.google.com/d/msgid/django-users/778f1f33-3c34-491e-a062-9527ec703bfd%40googlegroups.com?utm_medium=email&utm_source=footer> > . > For more options, visit https://groups.google.com/d/optout. > > > -- 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/57965c06-e757-487b-8937-cfd1c4b675d4%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.

