#33950: ModelChoiceField and chained prefetch_related(): queries made twice
----------------------------------+--------------------------------------
Reporter: Vincent Lefoulon | Owner: nobody
Type: Bug | Status: new
Component: Uncategorized | Version: 3.2
Severity: Normal | Resolution:
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
----------------------------------+--------------------------------------
Description changed by Vincent Lefoulon:
Old description:
> Hi!
>
> I have these three models:
>
> ```
> class Place(models.Model):
> name = models.CharField(max_length=255)
>
> class Visit(models.Model):
> date = models.DateField()
> place = models.ForeignKey(Place, on_delete=models.CASCADE,
> related_name="visits")
>
> class VisitDocument(models.Model):
> visit = models.ForeignKey(Visit, on_delete=models.CASCADE,
> related_name="documents")
> file = models.FileField()
> ```
>
> A form to edit a visit:
>
> ```
> class VisitForm(forms.ModelForm):
> class Meta:
> model = Visit
> exclude = ("place",)
>
> def __init__(self, *args, **kwargs):
> super().__init__(*args, **kwargs)
>
> self.fields["documents_to_delete"] =
> forms.ModelMultipleChoiceField(
> queryset=self.instance.documents.all(),
> required=False,
> )
> ```
>
> And a generic view for the places:
>
> ```
> class PlaceView(DetailView):
> queryset = Place.objects.prefetch_related("visits__documents")
>
> def get_context_data(self, **kwargs):
> context = super().get_context_data(**kwargs)
> if "visit_form" not in context:
> context["visit_forms"] = [
> VisitForm(instance=visit)
> for visit in self.object.visits.all()
> ]
>
> def post(self, request, *args, **kwargs):
> // Handle the form
> ```
>
> Despite the `prefetch_related("visits__documents")` call in my view,
> `ModelMultipleChoiceField()` doesn't detect that the documents of the
> visit (i.e. the form instance) are already fetched because
> `visit.documents.all()._prefetch_related_lookups` is null:
> https://github.com/django/django/blob/stable/3.2.x/django/forms/models.py#L1167
>
> So is in the view: `self.object.visits.all()._prefetch_related_lookups`
> is null as well.
>
> Many thanks!
New description:
Hi!
I have these three models:
{{{
class Place(models.Model):
name = models.CharField(max_length=255)
class Visit(models.Model):
date = models.DateField()
place = models.ForeignKey(Place, on_delete=models.CASCADE,
related_name="visits")
class VisitDocument(models.Model):
visit = models.ForeignKey(Visit, on_delete=models.CASCADE,
related_name="documents")
file = models.FileField()
}}}
A form to edit a visit:
{{{
class VisitForm(forms.ModelForm):
class Meta:
model = Visit
exclude = ("place",)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["documents_to_delete"] =
forms.ModelMultipleChoiceField(
queryset=self.instance.documents.all(),
required=False,
)
}}}
And a generic view for the places:
{{{
class PlaceView(DetailView):
queryset = Place.objects.prefetch_related("visits__documents")
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if "visit_form" not in context:
context["visit_forms"] = [
VisitForm(instance=visit)
for visit in self.object.visits.all()
]
def post(self, request, *args, **kwargs):
// Handle the form
}}}
Despite the {{{prefetch_related("visits__documents")}}} call in my view,
{{{ModelMultipleChoiceField()}}} doesn't detect that the documents of the
visit (i.e. the form instance) are already fetched because
{{{visit.documents.all()._prefetch_related_lookups}}} is null:
https://github.com/django/django/blob/stable/3.2.x/django/forms/models.py#L1167
So is in the view:
{{{self.object.visits.all()._prefetch_related_lookups}}} is null as well.
Many thanks!
--
--
Ticket URL: <https://code.djangoproject.com/ticket/33950#comment:1>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/01070182ca2cafe9-bc43b25f-3d51-4447-bb44-1c6490fc28f3-000000%40eu-central-1.amazonses.com.