i've been trying to implement a new feature on a django ecommerce project that i'm working on. i created a separate model in the models.py file just for key features and i linked this model to the product model using the manytomanyfield method. the problem is that i can't get the data to be output at all. when i try printing it, it just outputs None even when the field is populated. is there a better and cleaner way to implement this feature??
i've provided code bits below
views.py file
class ProductDetail(APIView):
def get_object(self, category_slug, product_slug):
try:
return Product.objects.filter(category__slug=category_slug).get(slug=product_slug)
except Product.DoesNotExist:
raise Http404
def get(self, request, category_slug, product_slug, format=None):
product = self.get_object(category_slug, product_slug)
feature = product.key_features
features_serializer = KeyFeatureSerializer(feature)
serializer = ProductSerializer(product)
print(feature)
return Response(serializer.data)
models.py file
class KeyFeature(models.Model):
name = models.CharField(max_length=100)
def __str__(self) -> str:
return self.name
class Product(models.Model):
category = models.ForeignKey(Category, related_name = 'products', on_delete = models.CASCADE)
name = models.CharField(max_length = 255)
slug = models.SlugField()
description = models.TextField(blank=True, null=True)
price = models.DecimalField(max_digits=6, decimal_places=2)
image = models.ImageField(upload_to='uploads/', blank=True, null=True)
thumbnail = models.ImageField(upload_to='uploads/', blank=True, null=True)
date_added = models.DateTimeField(auto_now_add=True)
key_features = models.ManyToManyField(KeyFeature, related_name='products')
class Meta:
ordering = ('-date_added',)
def __str__(self) -> str:
return self.name
serializers.py file
from rest_framework import serializers
from .models import *
# a serializer allows python data to be converted to json form
class KeyFeatureSerializer(serializers.ModelSerializer):
class Meta:
model = KeyFeature
fields = ('id', 'name',)
class ProductSerializer(serializers.ModelSerializer):
key_features = KeyFeatureSerializer(many=True, read_only=True)
class Meta:
model = Product
fields = (
'id',
'name',
'get_absolute_url',
'description',
'price',
'get_image',
'get_thumbnail',
'key_features'
)
You are printing the manager not a QuerySet
, hence the None
, you can print this with:
from django.shortcuts import get_object_or_404
class ProductDetail(APIView):
def get_object(self):
return get_object_or_404(
Product,
category__slug=self.kwargs['category_slug'],
slug=self.kwargs['product_slug'],
)
def get(self, request, category_slug, product_slug, format=None):
product = self.get_object()
feature = product.key_features.all()
features_serializer = KeyFeatureSerializer(feature, many=True)
serializer = ProductSerializer(product)
print(feature)
return Response(serializer.data)
It also makes not much sense to call the KeyFeatureSerializer
itself, since it is a sub-serializer of your ProductSerializer
. In fact most of the boilerplate code can be removed by using a RetrieveAPIView
[drf-doc]:
from django.shortcuts import get_object_or_404
from rest_framework.generics import RetrieveAPIView
class ProductDetailView(RetrieveAPIView):
queryset = Product.objects.all()
serializer_class = ProductSerializer
def get_object(self):
return get_object_or_404(
self.get_queryset(),
category__slug=self.kwargs['category_slug'],
slug=self.kwargs['product_slug'],
)