aufziehvogel
aufziehvogel

Reputation: 7297

Get filtered object from a ForeignKey relation in django template

I am having a problem with djangos design choice not to allow model filtering in templates. Actually, I do understand its sense and I do not really want to break it, but currently I cannot see what's the best or usual method to circumvent my situation.

I am having a model Task with a foreign key user_solutions to another model Solution. Now I am iterating over all Tasks and if the user already has a solution for this task, I want to display both a tick and the link to his solution. Somewhat like this:

{% for task in tasks %}
    {{ task.title }}
    {% if task.user_solutions.filter(author=author).count() > 0 %}
        Tick!
        {{ task.user_solutions.get(author=author).get_absolute_url }}
    {% endif %}
{% endfor %}

Yes, it looks cruel querying the database two times for the same information and django template does not accept it like this (correctly).

However, the other approaches to not seem to work either:

So what else is there I can do? From the linked article I can only see that I could add a new template tag to allow querying from the template, but as said, I actually would like to follow djangos design principle if possible.

Upvotes: 1

Views: 2284

Answers (3)

drabo2005
drabo2005

Reputation: 1096

You can use django template tags like this: templatetags.py @register.inclusion_tag("template.html") def task_def(request): task = user_solutions.filter(author=author).count() if task >0: task.is_this_users = True task_url = task.user_solutions.get(author=author).get.absolute_url return {'task_url': task_url}

in the template file (.html) {% load templatetags %} and now you can use your return result here like you want {% for element in task_url %}

Upvotes: 0

Basti
Basti

Reputation: 252

You can add whatever you want to your tasks while in the view, so, in views.py, you could do something like this:

# in views.py
for task in tasks:
    if task.user_solutions.filter(author=author).count() > 0:
        task.is_this_users = True
        task.url = task.user_solutions.get(author=author).get.absolute_url

and then in your template:

{% for task in tasks %}
    {{ task.title }}
    {% if task.is_this_users %}
        Tick!
        {{ task.url }}
    {% endif %}
{% endfor %}

Upvotes: 1

Daniel Roseman
Daniel Roseman

Reputation: 599778

The Django way to do this is to create a custom template tag that accepts a user parameter and filters the queryset appropriately. It's just a couple of lines of code.

Django isn't dogmatic about "no logic in templates" (dogmaticism is frowned on in Python generally, aka "practicality beats purity"). It doesn't provide the ability to do that sort of thing natively in the template language, but that's why it has custom template tags at all: if your design requires it, and the simplest way to do it would be to query from the template, then that's what you should do.

Upvotes: 2

Related Questions