Home > Software design >  Django query fetch foreignkey association without N 1 queries in database
Django query fetch foreignkey association without N 1 queries in database

Time:09-22

I have two models, Product and Price. I have used the ForeignKey association of the Django models to define the association between product and price. the scenario is, one product can have multiple prices according to size. On the home page, I have to fetch all the products with their prices and need to show their price(probably base price). Following is the code that I tried.

class Product(BaseModel):
    name = models.CharField(max_length=50)
    category = models.ForeignKey(Category, null=True, on_delete=models.SET_NULL, help_text='Please add new category if not given.')
    image = models.ImageField(upload_to='images/')
    tag = models.ManyToManyField(Tag, help_text='You can add multiple tags')
    slug = models.SlugField(unique=True, null=True)
    time = models.TimeField(verbose_name='Time Required')


class Price(BaseModel):
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    size = models.FloatField(validators=[MinValueValidator(0)])
    amount = models.FloatField(validators=[MinValueValidator(0)])

Then in the view.py file

class ProductListView(ListView):
    model  = Product
    context_object_name = 'products'
    paginate_by = 32

    def get_context_data(self,*args, **kwargs):
        object = super(ProductListView, self).get_context_data(*args, **kwargs)
        object['categories'] = Category.objects.order_by('name')
        return object

    def get_queryset(self):
        return Product.objects.order_by('name')

In the template, I am able to get and loop through the categories and products but I am not able to access the related prices of each product. If I tried something in the get_context_data, will it cause N 1 queries to fetch prices for every product?

In the template I tried to use something like {{ product.price_set }} but it returns order.Price.None.

CodePudding user response:

use {{ product.price_set.all }}.

To avoid N 1 queries in your filter, use prefetch_related so it looks something like.

Product.objects.all().prefetch_related('price_set')

See prefetch_related in the Django documentation.

See also select related vs prefetch related

  • Related