Select_Related() Prefetch_Related() Django.How

Author avatar wrote on 06/06/2022

When the database has foreign keys, using select_related() and prefetch_related() can reduce the number of database requests and improve performance
  • https://docs.djangoproject.com/en/3.2/ref/models/querysets/#select-related
  • https://developpaper.com/djangos-select_related-and-prefetch_related-functions-to-optimize-queryset-queries/
  • Join Tables without related

  • you can foreign key and one-to-one values eg: article.author.name
  • but you will hit the DB every time when accessing related models
  • 
    artciles = Article.objects.all()
    
    e = Entry.objects.get(id=5) # Hits the database.
    b = e.blog # Hits the database again to get the related Blog object.
    

    Select_related()

  • an optional performance booster
  • avoid hitting the DB when accessing related models
  • is limited to single-valued relationships
  • foreign key and one-to-one.
  • 
    Artciles = Article.objects.select_related('reporter')
    
    e = Entry.objects.select_related('blog').get(id=5)
    

    Hits the database.
    
    b = e.blog 
    

    Doesn't hit the database, because e.blog has been prepopulated, in the previous query.
    Join in join
    
    b = Book.objects.select_related('author__hometown').get(id=4)
    p = b.author         # Doesn't hit the database.
    c = p.hometown       # Doesn't hit the database.
    

    Many foreign keys
    
    Comment.objects.select_related('user', 'article').all()
    

    Or
    
    Comment.objects.select_related('user').select_related('article').all()
    

    With Filter
    
    Entry.objects.filter(pub_date__gt=timezone.now()).select_related('blog')
    

    Or
    
    Entry.objects.select_related('blog').filter(pub_date__gt=timezone.now())
    

    Avoid redundent no need for 'pizzas' because it's included in 'pizzas__toppings'
    
    select_related('pizzas__toppings', 'pizzas')
    

    Clear the list of related fields added by past calls of select_related on a QuerySet
    
    without_relations = queryset.select_related(None)
    

    Prefetch_related()
  • an optional performance booster
  • avoid hitting the DB when accessing related models
  • does a separate lookup for each relationship
  • prefetch many-to-many and many-to-one objects
  • 
    pizzas = Pizza.objects.all().prefetch_related('toppings')
    

    Avoid redundent no need for 'pizzas' because it's included in 'pizzas__toppings'
    
    prefetch_related('pizzas__toppings', 'pizzas')