diff --git a/core/apps/accounts/admin/__init__.py b/core/apps/accounts/admin/__init__.py new file mode 100644 index 0000000..d802ffd --- /dev/null +++ b/core/apps/accounts/admin/__init__.py @@ -0,0 +1,2 @@ +from .user import * +from .like import * \ No newline at end of file diff --git a/core/apps/accounts/admin/like.py b/core/apps/accounts/admin/like.py new file mode 100644 index 0000000..f79fbc0 --- /dev/null +++ b/core/apps/accounts/admin/like.py @@ -0,0 +1,8 @@ +from django.contrib import admin + +from core.apps.accounts.models import Like + + +@admin.register(Like) +class LikeAdmin(admin.ModelAdmin): + list_display = ['id', 'user', 'product'] \ No newline at end of file diff --git a/core/apps/accounts/admin/user.py b/core/apps/accounts/admin/user.py new file mode 100644 index 0000000..e0d08e6 --- /dev/null +++ b/core/apps/accounts/admin/user.py @@ -0,0 +1,9 @@ +from django.contrib import admin +from django.contrib.auth.admin import UserAdmin as DjangoUserAdmin + +from core.apps.accounts.models import User + + +@admin.register(User) +class UserAdmin(DjangoUserAdmin): + pass \ No newline at end of file diff --git a/core/apps/accounts/apps.py b/core/apps/accounts/apps.py index 197bf14..cbf167a 100644 --- a/core/apps/accounts/apps.py +++ b/core/apps/accounts/apps.py @@ -4,3 +4,6 @@ from django.apps import AppConfig class AccountsConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'core.apps.accounts' + + def ready(self): + from . import admin \ No newline at end of file diff --git a/core/apps/accounts/migrations/0003_like.py b/core/apps/accounts/migrations/0003_like.py new file mode 100644 index 0000000..d5c6323 --- /dev/null +++ b/core/apps/accounts/migrations/0003_like.py @@ -0,0 +1,31 @@ +# Generated by Django 5.2 on 2025-08-28 17:23 + +import django.db.models.deletion +import uuid +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0002_alter_user_created_at'), + ('products', '0002_category_name_ru_category_name_uz_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='Like', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='likes', to='products.product')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='likes', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'likelar', + 'verbose_name_plural': 'likelar', + 'unique_together': {('user', 'product')}, + }, + ), + ] diff --git a/core/apps/accounts/models/__init__.py b/core/apps/accounts/models/__init__.py index 82da278..d802ffd 100644 --- a/core/apps/accounts/models/__init__.py +++ b/core/apps/accounts/models/__init__.py @@ -1 +1,2 @@ -from .user import * \ No newline at end of file +from .user import * +from .like import * \ No newline at end of file diff --git a/core/apps/accounts/models/like.py b/core/apps/accounts/models/like.py new file mode 100644 index 0000000..cf8c144 --- /dev/null +++ b/core/apps/accounts/models/like.py @@ -0,0 +1,15 @@ +from django.db import models + +from core.apps.shared.models import BaseModel +from core.apps.accounts.models import User +from core.apps.products.models import Product + + +class Like(BaseModel): + user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='likes') + product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='likes') + + class Meta: + verbose_name = 'likelar' + verbose_name_plural = 'likelar' + unique_together = ['user', 'product'] diff --git a/core/apps/accounts/urls.py b/core/apps/accounts/urls.py index ae0566c..7f4dd26 100644 --- a/core/apps/accounts/urls.py +++ b/core/apps/accounts/urls.py @@ -1,8 +1,11 @@ from django.urls import path, include from rest_framework_simplejwt.views import TokenObtainPairView +from core.apps.accounts.views import like as like_views urlpatterns = [ path('login/', TokenObtainPairView.as_view()), + path('/like/', like_views.LikeApiView.as_view()), + path('liked_products/', like_views.LikeProductListApiView.as_view()), ] \ No newline at end of file diff --git a/core/apps/accounts/views/like.py b/core/apps/accounts/views/like.py new file mode 100644 index 0000000..06473ad --- /dev/null +++ b/core/apps/accounts/views/like.py @@ -0,0 +1,34 @@ +from django.shortcuts import get_object_or_404 + +from rest_framework import views, permissions, generics +from rest_framework.response import Response + +from core.apps.accounts.models import Like +from core.apps.products.models import Product +from core.apps.products.serializers.product import ProductListSerializer + + +class LikeApiView(views.APIView): + permission_classes = [permissions.IsAuthenticated] + + def get(self, request, product_id): + product = get_object_or_404(Product, id=product_id) + like, created = Like.objects.get_or_create(product=product, user=request.user) + if created: + return Response({'success': True, 'message': "Liked"}, status=200) + like.delete() + return Response({'success': False, 'message': "Unliked"}, status=200) + + +class LikeProductListApiView(generics.GenericAPIView): + serializer_class = ProductListSerializer + permission_classes = [permissions.IsAuthenticated] + + def get(self, request): + products = Product.objects.filter(likes__user=request.user) + page = self.paginate_queryset(products) + if page is not None: + serializer = self.serializer_class(page, many=True, context={'user': request.user}) + return self.get_paginated_response(serializer.data) + serializer = self.serializer_class(products, many=True, context={'user': request.user}) + return Response(serializer.data, status=200) diff --git a/core/apps/products/serializers/product.py b/core/apps/products/serializers/product.py index 57c18c9..d1ee021 100644 --- a/core/apps/products/serializers/product.py +++ b/core/apps/products/serializers/product.py @@ -1,11 +1,17 @@ from rest_framework import serializers from core.apps.products.models import Product +from core.apps.accounts.models import Like class ProductListSerializer(serializers.ModelSerializer): + liked = serializers.SerializerMethodField(method_name='get_liked') + class Meta: model = Product fields = [ - 'id', 'name', 'image', 'price', 'description', - ] \ No newline at end of file + 'id', 'name', 'image', 'price', 'description', 'liked' + ] + + def get_liked(self, obj): + return Like.objects.filter(user=self.context.get('user'), product=obj).exists() \ No newline at end of file diff --git a/core/apps/products/views/product.py b/core/apps/products/views/product.py index ac715c9..2f1ae63 100644 --- a/core/apps/products/views/product.py +++ b/core/apps/products/views/product.py @@ -4,11 +4,11 @@ from rest_framework import generics from rest_framework.response import Response from core.apps.products.models import Product, Category -from core.apps.products.serializers import category as serializers +from core.apps.products.serializers import product as serializers class ProductListApiView(generics.GenericAPIView): - serializer_class = serializers.CategoryListSerializer + serializer_class = serializers.ProductListSerializer queryset = Product.objects.all() permission_classes = [] @@ -17,7 +17,7 @@ class ProductListApiView(generics.GenericAPIView): products = Product.objects.filter(category=category) page = self.paginate_queryset(products) if page is not None: - serializer = self.serializer_class(page, many=True) + serializer = self.serializer_class(page, many=True, context={'user': request.user}) return self.get_paginated_response(serializer.data) - serializer = self.serializer_class(products, many=True) + serializer = self.serializer_class(products, many=True, context={'user': request.user}) return Response(serializer.data, status=200)