All checks were successful
Build and Push Docker Image / build (push) Successful in 51s
- Implemented `Favorite` model with unique user-item constraint and timestamped records - Added `favorites:index` and `favorites:toggle` views with AJAX support for toggling favorites - Built templates and front-end assets for the favorites page and integration with item grids - Extended header with favorites link and dynamic counter - Added tests covering models, views, and templates for the favorites functionality - Updated admin to enable management of favorites via Django admin interface
74 lines
2.4 KiB
Python
74 lines
2.4 KiB
Python
from django.contrib import messages
|
|
from django.contrib.auth.decorators import login_required
|
|
from django.http import HttpRequest, HttpResponse, JsonResponse
|
|
from django.shortcuts import get_object_or_404, redirect, render
|
|
from django.urls import reverse
|
|
from django.utils.http import url_has_allowed_host_and_scheme
|
|
from django.views.decorators.http import require_POST
|
|
|
|
from favorites.models import Favorite
|
|
from items.models import Item
|
|
|
|
|
|
def wants_json_response(request: HttpRequest) -> bool:
|
|
return (
|
|
request.headers.get("x-requested-with") == "XMLHttpRequest"
|
|
or "application/json" in request.headers.get("accept", "")
|
|
)
|
|
|
|
|
|
@login_required
|
|
def index(request: HttpRequest) -> HttpResponse:
|
|
favorite_records = (
|
|
Favorite.objects.filter(user=request.user)
|
|
.select_related("item__category", "item__subcategory")
|
|
.prefetch_related("item__images")
|
|
.order_by("-created_at", "-id")
|
|
)
|
|
items = [favorite.item for favorite in favorite_records]
|
|
|
|
return render(request, "favorites/index.html", {
|
|
"items": items,
|
|
"favorite_count": len(items),
|
|
"favorite_item_ids": {item.id for item in items},
|
|
})
|
|
|
|
|
|
@login_required
|
|
@require_POST
|
|
def toggle(request: HttpRequest) -> HttpResponse:
|
|
item_id = request.POST.get("item_id")
|
|
item = get_object_or_404(Item, pk=item_id)
|
|
|
|
favorite = Favorite.objects.filter(user=request.user, item=item).first()
|
|
if favorite:
|
|
favorite.delete()
|
|
is_favorite = False
|
|
message = f"Товар «{item.name}» удалён из избранного."
|
|
else:
|
|
Favorite.objects.create(user=request.user, item=item)
|
|
is_favorite = True
|
|
message = f"Товар «{item.name}» добавлен в избранное."
|
|
|
|
favorite_count = Favorite.objects.filter(user=request.user).count()
|
|
next_url = request.POST.get("next") or reverse("favorites:index")
|
|
|
|
if wants_json_response(request):
|
|
return JsonResponse({
|
|
"item_id": item.pk,
|
|
"is_favorite": is_favorite,
|
|
"favorite_count": favorite_count,
|
|
"message": message,
|
|
})
|
|
|
|
messages.success(request, message)
|
|
|
|
if not url_has_allowed_host_and_scheme(
|
|
next_url,
|
|
allowed_hosts={request.get_host()},
|
|
require_https=request.is_secure(),
|
|
):
|
|
next_url = reverse("favorites:index")
|
|
|
|
return redirect(next_url)
|