다음은 쇼핑몰에서의 카트, 상품 옵션, 상품에 대한 모델이다.
#models.py
class Cart(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
inventory = models.ForeignKey(Inventory, on_delete=models.CASCADE, null=True)
quantity = models.IntegerField(default=1, null=False, blank=False)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.user.username
class Inventory(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='inventories')
color = models.CharField(max_length=20, null=True)
size = models.CharField(max_length=20, null=True)
stock = models.PositiveIntegerField(null=True)
def __str__(self):
return f"{self.product}, {self.color}, {self.size}, {self.stock}"
class Product(models.Model):
name = models.CharField(max_length=200)
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, related_name='products')
seller = models.ForeignKey(Seller, on_delete=models.CASCADE, related_name='products', null=True,default='')
slug = models.SlugField(null=False, allow_unicode=True)
create_at = models.DateTimeField(auto_now_add=True)
update_at = models.DateTimeField(auto_now=True)
description = models.TextField(blank=True)
price = models.PositiveIntegerField(blank=True, null=True)
sale_price = models.PositiveIntegerField(blank=True, null=True)
display = models.BooleanField('Display', default=True)
detail = RichTextUploadingField() # 편집기 스타일로 입력
image = models.ImageField(blank=True, upload_to='images/')
def __str__(self):
return self.name
카트에 담긴 상품수량과 가격으로 총 구매 예정 금액을 구하고자 할 때
cart -> inventory -> product를 거쳐 price에 접근할 수 있다.
이때 단순히 다음과 같이 코드를 작성했다고 했을 때,
# cart/views.py
# 장바구니 페이지 ------
@login_required(login_url='login')
def cart_list(request):
current_user = request.user
user_cart = Cart.objects.filter(user_id=current_user)
# 총 상품 가격 표시
total_price = 0
for i in user_cart:
price = i.inventory.product.price
qty = i.quantity
total_price += price*qty
context = {'carts': user_cart,
'total_price':total_price
}
return render(request, 'cart/list.html', context)
user_cart = Cart.objects.filter(user_id=current_user)
위와 같은 코드라면
price = i.inventory.product.price
에서 DB에 여러 쿼리를 보내면서 접근 횟수가 많아지게 된다.
하지만 다음과 같이 수정을 하면 쿼리 최적화가 가능하다.
# cart/views.py
# 장바구니 페이지 ------
@login_required(login_url='login')
def cart_list(request):
current_user = request.user
user_cart = Cart.objects.select_related('inventory__product')\
.filter(user_id=current_user)
# 총 상품 가격 표시
total_price = 0
for i in user_cart:
price = i.inventory.product.price
qty = i.quantity
total_price += price*qty
context = {'carts': user_cart,
'total_price':total_price
}
return render(request, 'cart/list.html', context)
user_cart = Cart.objects.select_related('inventory__product')\ .filter(user_id=current_user)
select_related를 사용하면 related objects(inventory, product)까지 가져와서 cache에 저장해놓게 된다. 따라서 inventory, product를 가져오기 위해 DB에 재접근하지 않고 cache를 통해 꺼내 쓸 수 있다.