Implementing Product Category and Listing APIs with Django REST Framework and Vue.js

Product Category API Endpoints

Two primary API endpoints are required for product categories:

  • Retrieve all categories with nested hierarchy (primary, secondary, tertiary)
  • Retrieve specific category details along with associated products

Category Serializers

Define serializers to handle nested category relationships:

from rest_framework import serializers
from .models import Product, ProductCategory

class ProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = "__all__"

class TertiaryCategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = ProductCategory
        fields = "__all__"

class SecondaryCategorySerializer(serializers.ModelSerializer):
    child_categories = TertiaryCategorySerializer(many=True)
    
    class Meta:
        model = ProductCategory
        fields = "__all__"

class PrimaryCategorySerializer(serializers.ModelSerializer):
    child_categories = SecondaryCategorySerializer(many=True)
    
    class Meta:
        model = ProductCategory
        fields = "__all__"

Category ViewSet Implementation

Create a viewset for category operations:

from .serializers import PrimaryCategorySerializer
from .models import ProductCategory

class ProductCategoryViewSet(mixins.ListModelMixin, 
                             mixins.RetrieveModelMixin, 
                             viewsets.GenericViewSet):
    """
    API endpoint for product category operations
    """
    
    queryset = ProductCategory.objects.filter(level=1)
    serializer_class = PrimaryCategorySerializer

URL Configuration

Register the category endpoint with the router:

from products.views import ProductCategoryViewSet

router.register(r'categories', ProductCategoryViewSet, basename="categories")

Access endpoints:

  • http://127.0.0.1:8000/categories/ for all categories
  • http://127.0.0.1:8000/categories/1/ for specific category details

Vue.js Integration for Category Display

Configure API calls in the Vue.js application:

// api.js configuration
const API_BASE = 'http://127.0.0.1:8000'

// Category data retrieval
const fetchCategories = () => {
  return axios.get(`${API_BASE}/categories/`)
}

Start the Vue development server:

npm run dev

Access the application at http://localhost:8080. Cross-origin requests must be handled.

Resolving CORS Issues in Django

Enable cross-origin resource sharing:

pip install django-cors-headers

Update Django settings:

# settings.py configuration
INSTALLED_APPS = [
    'corsheaders',
    # other apps
]

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    # remaining middleware
]

CORS_ALLOW_ALL_ORIGINS = True

Product Listing Implementation

Vue.js Product Data Retrieval

fetchProductData() {
  if (this.mode === 'search') {
    fetchProducts({
      query: this.searchTerm
    }).then(response => {
      this.products = response.data.results
      this.totalCount = response.data.count
    }).catch(error => {
      console.error(error)
    })
  } else {
    fetchProducts({
      page: this.currentPage,
      category: this.selectedCategory,
      sort: this.sortOrder,
      min_price: this.priceMin,
      max_price: this.priceMax
    }).then(response => {
      this.products = response.data.results
      this.totalCount = response.data.count
    }).catch(error => {
      console.error(error)
    })
  }
}

Backend Pagination Configuration

class ProductPagination(PageNumberPagination):
    """Custom pagination for product listings"""
    page_size = 12
    page_size_query_param = 'page_size'
    page_query_param = 'page'
    max_page_size = 100

Product Filter Implementation

import django_filters
from django.db.models import Q
from .models import Product

class ProductFilter(django_filters.FilterSet):
    """Filter set for product queries"""
    
    price_min = django_filters.NumberFilter("price", lookup_expr='gte')
    price_max = django_filters.NumberFilter("price", lookup_expr='lte')
    main_category = django_filters.NumberFilter("category", method='filter_by_category')
    
    def filter_by_category(self, queryset, name, value):
        """Filter products by any level of category hierarchy"""
        return queryset.filter(
            Q(category_id=value) | 
            Q(category__parent_id=value) | 
            Q(category__parent__parent_id=value)
        )
    
    class Meta:
        model = Product
        fields = ['price_min', 'price_max']

Product ViewSet Configuration

class ProductListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    """ViewSet for product listing operations"""
    
    queryset = Product.objects.all().order_by('id')
    pagination_class = ProductPagination
    serializer_class = ProductSerializer
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_class = ProductFilter
    search_fields = ['name', 'description_short', 'description_full']
    ordering_fields = ['units_sold', 'price']

API Endpoint Configurasion

# Main URL configuration
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from rest_framework.routers import DefaultRouter
from products.views import ProductListViewSet, ProductCategoryViewSet

router = DefaultRouter()
router.register(r'products', ProductListViewSet)
router.register(r'categories', ProductCategoryViewSet, basename='categories')

urlpatterns = [
    path('api/', include(router.urls)),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Key functionality implemented:

  • Category-based filtering
  • Price range filtering
  • Pagination with configurable page size
  • Full-text search across multiple fields
  • Sorting by sales volume and price

The category API provides hierarchical data while the product API supports complex filtering through category relationships at any level.

Tags: Django REST Framework Vue.js API Development Product Catalog Full-Stack Development

Posted on Thu, 11 Jun 2026 18:44:44 +0000 by faizulbari