Search code examples
pythondjangotemplatesdjango-filter

filtering reviews according to product django


I want my reviews that are on that particular product to be shown only on that product not on any other . I do not know how to filter it. Recently it is showing all the reviews on every product.

My models.py file is:

class Review(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    product = models.ForeignKey(Product , on_delete=models.CASCADE, null=True)
    date = models.DateTimeField(auto_now_add=True)
    text = models.TextField(max_length=3000 , blank=True)
    rate = models.PositiveSmallIntegerField(choices=RATE_CHOICES)
    likes= models.PositiveIntegerField(default=0)
    dislikes = models.PositiveIntegerField(default=0)

    def __str__(self):
        return self.user.full_name

my product models.py is:

class Product(models.Model):
    title = models.CharField(max_length=110)
    slug = models.SlugField(blank=True, unique=True)
    status = models.CharField(choices=CATEGORY_CHOICES, max_length=10)
    price = models.DecimalField(decimal_places=2, max_digits=6)
    quantity=models.IntegerField(default=1)
    discount_price=models.FloatField(blank=True, null=True)
    size = models.CharField(choices=SIZE_CHOICES, max_length=20)
    color = models.CharField(max_length=20, blank=True, null=True)
    image = models.ImageField(upload_to=upload_image_path)
    description = RichTextField(max_length=1000)
    featured = models.BooleanField(default=False)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    time_stamp = models.DateTimeField(auto_now_add=True)

my product detail views.py is:

class ProductDetailSlugView(ObjectViewedMixin,DetailView):
    queryset = Product.objects.all()
    context_object_name = "object_list"
    template_name = "product_detail.html"

    def get_context_data(self, *args ,**kwargs):
        context = super(ProductDetailSlugView , self).get_context_data(*args, **kwargs)
        context['reviews'] = Review.objects.all()
        # context['reviews'] = Review.objects.filter(product=self.request.product)
        cart_obj, new_obj = Cart.objects.new_or_get(self.request)
        context['cart'] = cart_obj
        # context['comments'] = Comment.objects.all()
        return context

my product_detail.html is:

<!--                            {% for review in reviews %}-->when i do this with my code it show me all the product
<!--                            <h1>{{review.text}}{{review.rate}}</h1>-->
<!--                            {% endfor %}-->
                            {% for review in product.review_set.all %}
                                     {{ review.text }}
                            {% endfor %}


Solution

  • You do not need to make a query separately for your reviews. You can simply loop over them using your instance of Product in the template. Also for some reason you have set context_object_name = "object_list" try this:

    {% for review in object.review_set.all %}
        {{ review.text }}
    {% endfor %}
    

    Here review_set is simply the default related_name set by Django which is the related models name in lowercase with _set appended to it. You can chose to set the related name yourself like so if you want:

    product = models.ForeignKey(Product, related_name='reviews', on_delete=models.CASCADE, null=True)
    

    Anyway if you insist on modifying the view you can simply do this:

    class ProductDetailSlugView(ObjectViewedMixin,DetailView):
        queryset = Product.objects.all()
        context_object_name = "object_list"
        template_name = "product_detail.html"
        
        def get_context_data(self, *args ,**kwargs):
            context = super(ProductDetailSlugView , self).get_context_data(*args, **kwargs)
            context['reviews'] = Review.objects.filter(product=self.object)
            cart_obj, new_obj = Cart.objects.new_or_get(self.request)
            context['cart'] = cart_obj
            # context['comments'] = Comment.objects.all()
            return context
    

    And then you can use this:

    {% for review in reviews %}
        {{ review.text }}
    {% endfor %}