Reputation: 7297
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:
Task.get_current_user_solution()
, because in the model I do not know which user is logged inTask.get_user_solution(user)
, because I cannot pass arguments through the templatecurrent_users_solutions
(with Task.id
as index), because in the template, I cannot use combined variables to access dictionaries (and the index to access it would of course be task.id
)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
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
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
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