Implementing Product Details and User Favorites in Django REST Framework
Using ViewSets for Product Detail API
Enable product detail retrieval by adding mixins.RetrieveModelMixin to the viewset:
class ProductListViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
Product Image Serilaization
For product images, use nested serialization to handle foreign key relationships:
class ProductImageSerializer(serializers.ModelSerializer):
class Meta:
model = ProductImage
fields = ("image",)
class ProductSerializer(serializers.ModelSerializer):
category = CategorySerializer()
images = ProductImageSerializer(many=True)
class Meta:
model = Product
fields = '__all__'
Hot Products Filter Implementation
Add is_hot to the filter fields in the filter class:
class ProductFilter(django_filters.FilterSet):
class Meta:
model = Product
fields = ['price_min', 'price_max', 'is_hot']
Set is_hot=True in the admin interface to display products as hot items.
User Favorites API Implementation
Serializer Configuration
from rest_framework import serializers
from user_operations.models import UserFavorite
from rest_framework.validators import UniqueTogetherValidator
class UserFavoriteSerializer(serializers.ModelSerializer):
user = serializers.HiddenField(
default=serializers.CurrentUserDefault()
)
class Meta:
validators = [
UniqueTogetherValidator(
queryset=UserFavorite.objects.all(),
fields=('user', 'product'),
message="Already favorited"
)
]
model = UserFavorite
fields = ("user", "product", 'id')
The validator ensures users can only favorite a product once.
ViewSet Implementation
from rest_framework import viewsets, mixins
from user_operations.models import UserFavorite
from user_operations.serializers import UserFavoriteSerializer
class UserFavoriteViewSet(viewsets.GenericViewSet,
mixins.ListModelMixin,
mixins.CreateModelMixin,
mixins.DestroyModelMixin):
serializer_class = UserFavoriteSerializer
def get_queryset(self):
return UserFavorite.objects.filter(user=self.request.user)
CreateModelMixin: Add favoritesDestroyModelMixin: Remove favoritesListModelMixin: Retrieve favorited products
URL Configuration
from user_operations.views import UserFavoriteViewSet
router.register(r'userfavorites', UserFavoriteViewSet, basename="userfavorites")
Permission and Authentication
Custom Permission Class
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj.user == request.user
Enhanced ViewSet with Security
class UserFavoriteViewSet(viewsets.GenericViewSet,
mixins.ListModelMixin,
mixins.CreateModelMixin,
mixins.DestroyModelMixin):
serializer_class = UserFavoriteSerializer
permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
lookup_field = 'product_id'
def get_queryset(self):
return UserFavorite.objects.filter(user=self.request.user)
Key configurations:
permission_classes: Restrict access to authenticated usersauthentication_classes: Support JWT and session authenticationlookup_field: Use product_id for object lookupget_queryset(): Filter results to current user's data
Frontend Integration
Configure API endpoints for frontend operations:
// Add to favorites
export const addFavorite = params => {
return axios.post(`${API_BASE}/userfavorites/`, params)
}
// Remove favorite
export const removeFavorite = productId => {
return axios.delete(`${API_BASE}/userfavorites/`+productId+'/')
}
// Get all favorites
export const getAllFavorites = () => {
return axios.get(`${API_BASE}/userfavorites/`)
}
// Check favorite status
export const checkFavorite = productId => {
return axios.get(`${API_BASE}/userfavorites/`+productId+'/')
}
Frontend components should display "Favorited" status based on API responses and use product IDs for deletion operations.