Search code examples
pythondjangodjango-templatessubscription

How to check if a user is subscribed to a product in Django template


I am working on a Django project whereby I want to check if a user is subscribed to a product or not. I have created in my models.py several model instances and I am stuck on how to check if the user is subscribed inside the template. Here is my template where I loop through the fetched data:

<ul>
{% for content in content %}
{% if content.model.is_premium and user.is_subscribed %}
       <li>Premium</li>
 {% else %}
  <li>Not premium</li>
  {% endif %}
 {% endfor %}
 </ul>

Here is my views.py :

@login_required(login_url='/user/login')
def homepage(request):
    content = ModelContent.objects.all()
    categorys = Category.objects.all()
    models = MyModels.objects.all()
    suggestions = MyModels.objects.all()[:3]
    # profiles = Profile.objects.filter(user__is_creator=True)
    context = {"categorys": categorys, "models": models, "content":content, "suggestions":suggestions}
    return render(request, 'users/home.html', context)

And here is the models.py:

User = get_user_model()
class MyModels(models.Model):
    owner = models.ForeignKey(Profile, on_delete=models.CASCADE, null=False, blank=False)
    name = models.CharField(max_length=500, null=False, blank=False)
    username = models.CharField(max_length=500, null=False, blank=False, unique=True)
    title = models.CharField(max_length=500, null=False, blank=False)
    description = models.TextField(max_length=500, null=False, blank=False)
    image = models.ImageField(upload_to='img',  blank=True, null=True)
    placeholder = models.ImageField(upload_to='img',  blank=True, null=True)
    sex = models.CharField(max_length=50, choices=SEX_CHOICES, default=NONE)
    category = models.ForeignKey(Category, on_delete=models.CASCADE, null=False, blank=False)
    content_id = models.UUIDField(default=uuid.uuid4, primary_key=True, unique=True, editable=False)
    created = models.DateField(auto_now_add=True)
    is_popular = models.BooleanField(default=False)
    is_premium = models.BooleanField(default=False)
    # posted_content = models.ManyToManyField('ModelContent', related_name='model_content')

    def __str__(self):
        return self.username
class ModelContent(models.Model):
model = models.ForeignKey(MyModels, on_delete=models.CASCADE, null=False, blank=False )
title = models.CharField(max_length=500, null=False, blank=False)
date = models.DateTimeField(auto_now_add=True)
content_id = models.UUIDField(default=uuid.uuid4, primary_key=True, unique=True, editable=False)

class Meta:
    ordering = ['-date']

def __str__(self):
    return str(self.title)

class Subscription(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='subscriptions_to_product')
    model = models.ForeignKey(MyModels, on_delete=models.CASCADE, related_name='subscriptions_from_subscriber')
    is_subscribed = models.BooleanField(default=False)

    def __str__(self):
        return f"{self.user.username} subscribed to {self.model.username}"

The views.py is inside an app called 'users' while the models.py is inside an app called 'posts'. I have tried doing this :

{% for content in content %}
    {% if content.model.is_premium %}
        {% with subscription=request.user.subscriptions_to_product.filter(model_id=content.model_id).first %}
            {% if subscription and subscription.is_subscribed %}
                <li>User Subscribed</li>
            {% else %}
                <li>User Not Subscribed</li>
            {% endif %}
        {% endwith %}
    {% else %}
        <li>Not premium</li>
    {% endif %}
{% endfor %}

But it did not work.


Solution

  • This is not the task of the template. Templates should be used only for rendering. Not for business logic. You can use an Exists subquery [Django-doc]:

    from django.db.models import F
    from django.db.models.functions import Exists
    
    @login_required(login_url='/user/login')
    def homepage(request):
        content = ModelContent.objects.annotate(
            is_subscriped=Exists(
                Subscription.objects.filter(
                    model__modelcontent=OuterRef('pk'),
                    user=request.user,
                    is_subscribed=True,
                )
            )
        )
        categorys = Category.objects.all()
        suggestions = MyModels.objects.all()[:3]
        context = {
            'categorys': categorys,
            'content': content,
            'suggestions': suggestions,
        }
        return render(request, 'users/home.html', context)

    In the template, you then render this as:

    {% for content in content %}
        {% if content.model.is_premium %}
            {% if content.is_subscribed %}
                <li>User Subscribed</li>
            {% else %}
                <li>User Not Subscribed</li>
            {% endif %}
        {% else %}
            <li>Not premium</li>
        {% endif %}
    {% endfor %}