Search code examples
djangodjango-modelsdjango-templatesdjango-filter

How to compare IntegerChoice values in Django Templates


I intend to compare the value of an IntegerChoice inside Django Template :

class SomeModel(models.Model):
    class Answer(models.IntegerChoices):
        NO = 0, _('No')
        YES = 1, _('Yes')
    
        __empty__ = _('(Unknown)')
    answer = models.IntegerField(choices=Answer.choices)

SomeModel.objects.create(answer=0)
somemodel = SomeModel.objects.filter(answer=0)

Inside template :

{% if somemodel.answer == SomeModel.Answer.YES %}
    ...
{% else %}
    <h1>{{ somemodel.get_answer_display() }}</<h1>
{% endif %}

Yet, this does not get inside the true if case, and also does not like "()" at the end of "SomeModel.get_answer_display" with the following message :

Could not parse the remainder: '()' from 'SomeModel.get_answer_display()'

Inside view:

class BrowseView(View):
    @method_decorator(login_required(login_url='/login/'))
    def get(self, request):
        somemodel = SomeModel.objects.all()
        return render(self.request, 'browse/index.html',
                      {
                       'somemodel': somemodel
                      })

How can I make the filter work as expected?


Solution

  • In templates you do not call a function: in case something is a callable, Django will call the callable with no parameters, you thus render this with:

    {% if somemodel.answer == SomeModel.Answer.YES %}
        …
    {% else %}
        <h1>{{ somemodel.get_answer_display }}</<h1>
    {% endif %}

    You should also work with a model object, so somemodel, not SomeModel.

    In your view, you will need to pass both the somemodel object and a reference to the SomeModel class:

    from django.contrib.auth.mixins import LoginRequiredMixin
    
    class BrowseView(LoginRequiredMixin, View):
        login_url = '/login/'
        
        def get(self, request):
            somemodel = SomeModel.objects.all()
            return render(
                self.request,
                'browse/index.html',
                {'somemodel': somemodel, 'SomeModel': SomeModel}
            )

    Here somemodel is also not a model object, it is a QuerySet (a collection) of SomeModels. You thus should enumerate over these:

    from django.contrib.auth.mixins import LoginRequiredMixin
    
    class BrowseView(LoginRequiredMixin, View):
        login_url = '/login/'
    
        def get(self, request):
            somemodels = SomeModel.objects.all()
            return render(
                self.request,
                'browse/index.html',
                {'somemodels': somemodels, 'SomeModel': SomeModel}
            )

    and in the template enumerate over the collection:

    {% for somemodel in somemodels %}
        …
    {% endfor %}

    Note: You can limit views to a class-based view to authenticated users with the LoginRequiredMixin mixin [Django-doc].