Search code examples
django-modelsdjango-queryset

Django - how to use multilevel join in models


I am beginner in python-Django and I am trying to build a e-commorce site. I have created a model for product Detail and product images. Here is my models:

class ProductDetail(models.Model):        
    product= models.ForeignKey(Product, on_delete=models.CASCADE)
    category= models.ForeignKey(ProductCategory, on_delete=models.CASCADE)
    sub_category= models.ForeignKey(ProductSubCategory, on_delete=models.CASCADE)    
    created_at= models.DateTimeField(auto_now_add=datetime)
    updated_at= models.DateTimeField(blank=True, null=True)
    deleted_at= models.DateTimeField(blank=True, null=True)
    

    # def __str__(self):
    #     return self.product

class ProductImage(models.Model):      
    img_type_choices = (
        ('Primary', "Primary"),
        ('Secondary', "Secondary"),
    )  
    product= models.ForeignKey(Product, on_delete=models.CASCADE)
    img= models.FileField(upload_to="shop/product_images", default="")
    type= models.CharField(max_length=12, choices=img_type_choices, default='Primary')
    created_at= models.DateTimeField(auto_now_add=datetime)
    updated_at= models.DateTimeField(blank=True, null=True)
    deleted_at= models.DateTimeField(blank=True, null=True)    

I using below code for products:

from shop.models import ProductSubCategory, ProductImage, ProductCategory, Product, ProductDetail

def index(request):
   products = ProductDetail.objects.values('product__name','product__product_id', 'product__price', 'product__desc', 'category__name', 'sub_category__name', 'category')

Now I want all images with product object

Now I am not getting how to get all images related to a products along with these object


Solution

  • I'm not sure why you're using .values(). It get rid of the Model layer by outputing dicts which make you loose a lot of Model capabilities.

    I would do something like this:

    qs = ProductDetail.objects.all()
    qs = qs.select_related("product", "category", sub_category)
    qs = qs.prefetch_related("product__productimage_set")
    

    .select_related() will results in SQL joins which make product_detail.product accessible without additional query. This is very powerful to retrieve related models.

    .prefetch_related() provide similar benefit but with reverse foreign keys. (At the cost of 1 SQL query per model).
    Accessing product_detail.product.productimage_set.all() will give you all ProductImages tied to product_detail.product without needing additional queries.

    Note that productimage_set is the default related_name generated by Django. You can define your own.

    class ProductImage(models.Model):      
        product= models.ForeignKey(Product, on_delete=models.CASCADE, related_name="images")