141 lines
4.8 KiB
Python
141 lines
4.8 KiB
Python
from django.contrib.auth.decorators import login_required
|
|
from django.db.models import Avg, Q
|
|
from django.db.models.functions import Coalesce
|
|
from django.shortcuts import get_object_or_404, redirect, render
|
|
|
|
from cart.views import add_to_cart
|
|
from .models import Product, WishlistItem
|
|
|
|
SORT_LABELS = {
|
|
'newest': 'Newest first',
|
|
'rating': 'Top rated',
|
|
'price_asc': 'Price low to high',
|
|
'price_desc': 'Price high to low',
|
|
}
|
|
|
|
|
|
def _normalized_categories():
|
|
categories = [choice[0] for choice in Product.CATEGORY_CHOICES]
|
|
raw_categories = Product.objects.values_list('category', flat=True).distinct()
|
|
for value in raw_categories:
|
|
cleaned = (value or '').strip()
|
|
if cleaned and cleaned not in categories:
|
|
categories.append(cleaned)
|
|
return categories
|
|
|
|
|
|
def product_list(request, category=None):
|
|
products = Product.objects.annotate(final_price=Coalesce('discount_price', 'price'))
|
|
query = request.GET.get('q', '').strip()
|
|
sort = request.GET.get('sort', '')
|
|
selected_category = (request.GET.get('category', category) or '').strip()
|
|
featured_raw = (request.GET.get('featured') or '').strip().lower()
|
|
selected_featured = featured_raw in {'1', 'true', 'yes'}
|
|
|
|
if selected_category:
|
|
products = products.filter(category__iexact=selected_category)
|
|
|
|
if selected_featured:
|
|
products = products.filter(featured=True)
|
|
|
|
if query:
|
|
products = products.filter(
|
|
Q(name__icontains=query)
|
|
| Q(description__icontains=query)
|
|
| Q(category__icontains=query)
|
|
)
|
|
|
|
if sort == 'price_asc':
|
|
products = products.order_by('final_price')
|
|
elif sort == 'price_desc':
|
|
products = products.order_by('-final_price')
|
|
elif sort == 'newest':
|
|
products = products.order_by('-created_at')
|
|
elif sort == 'rating':
|
|
products = products.order_by('-rating')
|
|
else:
|
|
products = products.order_by('-featured', '-created_at')
|
|
|
|
categories = _normalized_categories()
|
|
wishlist_ids = set()
|
|
if request.user.is_authenticated:
|
|
wishlist_ids = set(WishlistItem.objects.filter(user=request.user).values_list('product_id', flat=True))
|
|
|
|
active_filters = []
|
|
if query:
|
|
active_filters.append(f'Search: “{query}”')
|
|
if selected_category:
|
|
active_filters.append(f'Category: {selected_category}')
|
|
if selected_featured:
|
|
active_filters.append('Featured only')
|
|
if sort:
|
|
active_filters.append(f'Sort: {SORT_LABELS.get(sort, sort)}')
|
|
|
|
aggregates = products.aggregate(avg_rating=Avg('rating'))
|
|
|
|
return render(
|
|
request,
|
|
'products/product_list.html',
|
|
{
|
|
'products': products,
|
|
'categories': categories,
|
|
'selected_category': selected_category,
|
|
'selected_featured': selected_featured,
|
|
'search_query': query,
|
|
'selected_sort': sort,
|
|
'wishlist_ids': wishlist_ids,
|
|
'products_count': products.count(),
|
|
'featured_count': products.filter(featured=True).count(),
|
|
'in_stock_count': products.filter(stock__gt=0).count(),
|
|
'discounted_count': products.filter(discount_price__isnull=False).count(),
|
|
'avg_rating': aggregates.get('avg_rating') or 0,
|
|
'active_filters': active_filters,
|
|
'has_active_filters': bool(active_filters),
|
|
},
|
|
)
|
|
|
|
|
|
def product_detail(request, product_id):
|
|
product = get_object_or_404(Product, id=product_id)
|
|
related_products = Product.objects.filter(category=product.category).exclude(id=product.id)[:4]
|
|
in_wishlist = False
|
|
if request.user.is_authenticated:
|
|
in_wishlist = WishlistItem.objects.filter(user=request.user, product=product).exists()
|
|
|
|
return render(
|
|
request,
|
|
'products/product_details.html',
|
|
{
|
|
'product': product,
|
|
'related_products': related_products,
|
|
'in_wishlist': in_wishlist,
|
|
},
|
|
)
|
|
|
|
|
|
@login_required
|
|
def toggle_wishlist(request, product_id):
|
|
product = get_object_or_404(Product, id=product_id)
|
|
item, created = WishlistItem.objects.get_or_create(user=request.user, product=product)
|
|
if not created:
|
|
item.delete()
|
|
|
|
next_url = request.GET.get('next') or request.META.get('HTTP_REFERER') or 'product_list'
|
|
if next_url.startswith('/'):
|
|
return redirect(next_url)
|
|
return redirect('product_list')
|
|
|
|
|
|
@login_required
|
|
def move_wishlist_to_cart(request, product_id):
|
|
item = get_object_or_404(WishlistItem, user=request.user, product_id=product_id)
|
|
response = add_to_cart(request, product_id)
|
|
item.delete()
|
|
return response
|
|
|
|
|
|
@login_required
|
|
def wishlist_view(request):
|
|
wishlist_items = WishlistItem.objects.filter(user=request.user).select_related('product')
|
|
return render(request, 'products/wishlist.html', {'wishlist_items': wishlist_items})
|