Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prefetch related django

I'm developping an application written in Django and I have some problems to do a correct request using select_related and prefetch_related

I have three models :

class Intervention(BaseModel):
    date = DateField()
    housing = ForeignKey('contract.Housing', related_name='interventions')

class Housing(BaseModel):
    address = CharField(max_length=CHAR_FIELD_LENGTH) 

class Tenant(BaseModel):
    name = CharField(max_length=CHAR_FIELD_LENGTH)
    phone = CharField(max_length=CHAR_FIELD_LENGTH, blank=True, null=True)
    housing = ForeignKey(Housing, related_name='tenants')

I am requesting on the model Interventions, if I want to have access to the housing informations, I just have to use select_related :

Interventions.object.select_related("housing").filter(...)

But I don't know how to access to the tenants using prefetch_related :

Interventions.object.select_related("housing").prefetch_related("housing__tenants") 

doesn't seems to work, because it makes a query everytime I try to access to the tenants list. Is there a way to access to the tenant list, and best, to do a filter on I (like first Tenant found which has no name).

Thanks for you answers.

Algelos

*Edit : Here is some code : *

I'm requesting like I said :

interventionPreventivesVisits = InterventionPreventiveVisit.objects.select_related("housing").prefetch_related("housing__tenants").filter(date__range=(self.weekDays[0], self.weekDays[len(self.weekDays)-1]))

self.weekDays is a table of days, to display the interventions in a calendar.

And then, I want to display the tenant which has no name :

In my template, I loop through the interventions :

{%for inter in interventions %}
    {%if day == inter.date %}
        {{ inter | get_schedule_html_formated | safe}}
    {%endif%}
{% endfor %}

And I have a templateTag to display the HTML :

def get_schedule_html_formated(intervention):
    housingTenant = None
    for tenant in intervention.housing.tenants.all(): # Here it does a query
        if tenant.name is not None:
            housingTenant = tenant
    ....

and then I write and return my html

I'm searching a way to set housingTenant without doing a new query.

Is that better :) ?

like image 826
bbusseuil Avatar asked Dec 03 '13 09:12

bbusseuil


2 Answers

From here https://docs.djangoproject.com/en/dev/ref/models/querysets/#prefetch-related

select_related works by creating an SQL join and including the fields of the related object in the SELECT statement. For this reason, select_related gets the related objects in the same database query. However, to avoid the much larger result set that would result from joining across a ‘many’ relationship, select_related is limited to single-valued relationships - foreign key and one-to-one.

prefetch_related, on the other hand, does a separate lookup for each relationship, and does the ‘joining’ in Python.

update for comment:

it is better to place filter first here (order in django can affect on results):

interventionPreventivesVisits = InterventionPreventiveVisit.objects.filter(
    date__range=(self.weekDays[0], self.weekDays[len(self.weekDays)-1])
).select_related("housing"
).prefetch_related("housing__tenants")
like image 195
ndpu Avatar answered Sep 24 '22 07:09

ndpu


Try using this:

interventionPreventivesVisits = InterventionPreventiveVisit.objects.\
    prefetch_related("housing__tenants").\
    filter(date__range=(self.weekDays[0], self.weekDays[len(self.weekDays)-1]))
like image 32
Arpit Avatar answered Sep 22 '22 07:09

Arpit