A_K
A_K

Reputation: 912

Why is Conditional Expressions adding new Items to a list view

I am trying to add a Post to a list view, the Home list view has already an Item context.

In my project, a user can add a post and add an item each is a different app with different models.

So In my Home list view, I have my items looped and in each item, it is showing the user related to it.

What I am trying to do is check if this item.user has a post which is admin_approved=Truerelated to the user and if it does exist a button show appears in the page linking to another page with these posts.

So if there are Zero posts related to the user or posts available but admin_approved=False or not yet admin_approved=True the button should not appear but if there is 1 or more posts that are admin_approved=Truethe button should appear.

I have tried to annotate the queryset but the issue is that when a user has 2 posts one which is approved and another not approved, 2 items appears one with the button and one without the button and duplication takes place in the homepage List view

I have tried to use .distinct() but it didn't work items are still duplicated

Here is the models.py

class Post(models.Model):
    designer = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(max_length=100, unique=True)
    admin_approved = models.BooleanField(default=False)

here is the views

from .models import Item
from django.db.models import Case, When, BooleanField, Q

class HomeView(ListView):
    model = Item
    paginate_by = 12
    template_name = "home.html"
    ordering = ['-timestamp']

    def get_queryset(self):
        has_post = Case(
            When(Q(designer__post__isnull=False) & Q(designer__post__admin_approved=True), then=True),
            default=False,
            output_field=BooleanField()
        )
        return super().get_queryset().annotate(has_post=has_post).distinct()

here is the template

{% for item in object_list %}
    {{ item.title }}
    {% if item.has_post %}
        SHOW BUTTON
    {% else %}
        HIDE BUTTON
    {% endif %}
{% endfor %}

here is the item model

class Item(models.Model):
    designer = models.ForeignKey(
        User, on_delete=models.CASCADE)
    title = models.CharField(max_length=100)

Upvotes: 1

Views: 96

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476614

It will repeat each Item for each designer__post combination, since you do not use a "fold" function.

You can make use of an Exists subquery [Django-doc] instead:

from django.db.models import Exists, OuterRef

class HomeView(ListView):
    model = Item
    paginate_by = 12
    template_name = "home.html"
    ordering = ['-timestamp']

    def get_queryset(self, *args, **kwargs):
        return super().get_queryset(*args, **kwargs).annotate(
            has_post=Exists(
                Post.objects.filter(
                    designer_id=OuterRef('designer_id'),
                    admin_approved=True
                )
            )
        )

Upvotes: 1

Related Questions