Filter within includes in django template - django

I am utilizing an includes within my template, but would only like to send a splice of the django queryset through the template. I don't want to splice in my view, because this is apart of a larger for loop that will be continually calling the include with different subsections. Here was my wishful thinking:
{% for g in gl %}
{% include 'includes/file.html' with ps=ps|id:g.id %}
{% endfor %}

You should create a filter tag that will receive your queryset and return a filtered one.... you can find details here:
https://docs.djangoproject.com/en/2.1/howto/custom-template-tags/

Related

Could not parse the remainder: '{{comment.post}}=={{blog.post}}' from '{{comment.post}}=={{blog.post}}'

I am making a blog website and I have to add comments to my post for that I have to check which post the comment is associated with and I am writing this line
{% if {{comment.post}}=={{blog.post}} %}
I know this line won't work because {%%} and {{}} cannot be used in the same line so does anyone has a solution for this.
In a template tag, you do not use the double curly brackets, but just the variables:
{% if comment.post == blog.post %}
…
{% endif %}
That being said, please do not filter in a template. Business logic belongs to the models or views. If you use relations, like a ForeignKey [Django-doc], or a ManyToManyField [Django-doc], then Django adds managers to the corresponding models. This also means it fetches the related comments by a query to the database. Especially if the number of comments will increase, eventually filtering in the template will no longer be feasible.
{% if comment.post == blog.post %}
…
{% endif %}
this will work well

Django: If value exists in database, pass it as a variable from view to template

I am new to coding and new to Django. I searched stackoverflow for my question but didn't find what I was looking for:
What I am trying to do is check if certain values are in my database and if yes, pass it as a variable to the template. The values will be items of a dropdown menu.
If I have for example a database with bicycle1 to bicycleN I'd like to check if the value of the attribute "handlebar" of each database-object matches a certain manufacturer. If yes, pass it to the template so it can appear in the dropdown menu to later filter the results.
First I thought I should check in the template itself and thought about something like this:
bicyle_list.html
<ul id='dropdown1' class='dropdown-content'>
{% for bicyle in bicycles %}
{% with manufacturerA=False %}
{% if manufacturerA == False and bicycle.handlebar == "manufacturerA" %}
<li>ManufacturerA</li>
{% manufacturerA=True %}
{% endif %}
{% endwith %}
{% endfor %}
But as I understand the template should only contain rendering logic. (Besides, I`d have to use boolean variables in the for-loop, because a manufacturer should only appear once in the dropdown menu even if there are several bicycles with that certain handlebar. Changing the value of variables in a template seems quite complicated to me.)
In the views.py I thought about this but don't know how to work with conditions and the rendering-method:
views.py
bicycles = Bicycle.objects.all()
for bicycle in bicyles:
if bicycle.handlebar == "manufacturerA":
manufacturerA= "manufacturerA"
if bicycle.handlebar == "manufacturerB":
manufacturerB= "manufacturerB"
#if variable manufacturerA exists, pass it to the template – if not, not! Same with manufacturerB
#But how to include in return render(..)?
return render(request, 'shop/bicycle_list.html', {'bicycles': bicycles})
Do you have any idea how to pass optional variables?
You can obtain a list of distinct manufacturers with:
def some_view(request):
manufacturers = Bicycle.objects.values_list('handlebar', flat=True).distinct()
return render(request, 'shop/bicycle_list.html', {'manufacturers': manufacturers})
<ul id='dropdown1' class='dropdown-content'>
{% for manufacturer in manufacturers %}
<li>{{ manufacturer }}</li>
{% endfor %}
</ul>
You however might want to make a model for the manufacturer, and work with a many-to-one relationship [Django-doc].

Apply filter to result of Django custom template tag (like i18n trans)

We have a Django project with a legacy translation module that stores translations in the database, and does not use Django i18n (gettext).
We have written custom template tags {% db_trans ... %} that work like Django's default {% trans ... %}, but there is one trick we cannot duplicate.
In this example, "tree" (English) translates to "boom" (Dutch).
In my Django template, if I use default i18n and write {% trans "tree" %} I will see the result boom. When I want to use this as a title, I use the capfirst filter like this {% trans "tree"|capfirst %}, and the result will be Boom. Note the capital B.
This seems to be a special trick. Our db_trans custom tag (based on simple_tag) capitalizes the input before translation. Since there is no translation in the database for Tree, {% db_trans "tree"|capfirst %} renders its default (untranslated) value, Tree.
I now about {% filter capfirst %}...{% endfilter %} and will probably use it if we cannot find an easy solution.
I have checked the Django source code and I saw that {% trans ... %} is not based on simple_tag and does quite a lot of text argument parsing.
My question: is there a package or snippet that allows a filter specified as shown above to be applied to the result of a custom tag?
If you make your template tag a filter, then you can chain it with capfirst built-in filter
from django import template
register = template.Library()
#register.filter
def db_trans(word, request):
return do_the_translation(word, request)
Then in the html it would look like this
{{ 'tree'|db_trans:request|capfirst }}

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:
I cannot add a method Task.get_current_user_solution(), because in the model I do not know which user is logged in
I cannot add a method Task.get_user_solution(user), because I cannot pass arguments through the template
I cannot query information in the view and save it into a dictionary current_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.
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.
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 %}
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 %}

loop in Django template: how to control the loop iterator?

I'm using Django to show a list of posts. Each post has a 'is_public' field, so if one post's 'is_public' equals to False, it should not be shown to the user. Also, I want to show a fixed number of posts in one page, but this number can be changing depending on views.
I decided to crop the queryset in template as a few views are using the same template, generating it in the view means a lot of repeated codes.
If written in python, it should look like this:
i=number_of_posts_to_show_in_one_page
while i:
if qs[i].is_public == True:
#show qs[i] to the page
i--
As the django template does not support while loop and for loop seems hard to control, is there a way of achieving this? Or should I do it in another way?(One idea is to crop the qs before looping)Thanks!
Update:
I've written this template tag to pre-process the queryset:
#register.simple_tag(takes_context=True)
def pre_process_list(context,list,numbers):
#if not user.has_perm('admin'):
context['result_list']=list.filter(is_public=True, is_removed=False)[0:numbers]
#else:
#context['result_list']=list[0:numbers]
return ''
Before using for loop in the template, I'll pass the queryset to this templage tag, and use a simple for loop to show its result.
If in the future I want to show non-public posts to admins(which is not decided yet), I can write in some logic like the commented ones, and have them styled differently in the template.
{% for post in posts %}
{% if post.is_public %}
{{ post }}
{% endif %}
{% endfor %}
Though this would be a perfect use case for a manager.
You could write a simple manager that filters public posts.
class PublicPostManager(models.Manager):
def get_query_set(self):
return super(PublicPostManager, self).get_query_set().filter(is_public=True)
Then you would add it to your Post Class:
class Post(models.Model):
...
public = PublicPostManager()
Then you could pass post.public.all() as public_posts to your template and simplify your loop:
{% for post in public_posts %}
{{ post }}
{% endfor %}
#arie has a good approach with the manager, but you can easily do the same without writing a manager:
# View
posts = Post.objects.filter(is_public=True) # or use the manager
# Now, you can either limit the number of posts you send
# posts = posts[:5] (only show five in the view)
return render_to_response('foo.html',{'posts':posts})
# Template
# Or you can do the limits in your template itself:
{% for post in posts|slice:":5" %}
{{ post }}
{% endfor %}
See the slice filter on more information.
However, since this is a common operation, with django 1.3 you can use class based views to automate most of this.