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 categorieshttp://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.