How to use arrays in loop with if statment in django template - django

I want to choose include button_free when hour_1 is 0 or choose button_busy when hour_0 is 1
view
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['hour_1'] = [0,0,1,1,0]
context['range_5'] = [0, 1, 2, 3, 4]
return context
`
part of template
{% for schedule_part in range_5 %}
{% if hour_1.schedule_part == 0 %}
{% include "users/button_free.html" with button_id=hour_1.schedule_part %}
{% else %}
{% include "users/button_busy.html" with button_id=hour_1.schedule_part %}
{% endif %}
{% endfor %}
hour_1 is for example [0,0,1,1,0]
Displays only button_busy
When debugging hour_1.schedule_par raises VariableDoesNotExist exception.
How should I get to the hour_1 elements

Related

{% url ... %} templatetag in Django included template not seeing variable

I'm experiencing strange behaviour in an included template which I can't figure out.
urls.py
urlpatterns = (
path(
"items/",
views.list_view,
name="list-view",
),
path(
"item/<int:pk>/",
views.detail_view,
name="detail-view",
),
)
views.py
def list_view(request):
items = Item.objects.all()
return render(request, "parent_template.html", context={"items": items})
def detail_view(request, pk):
item = get_object_or_404(Item, pk=pk)
return render(request, "detail_template.html", context={"item": item}
parent_template.html
{% for item in items %}
Parent: {{ item.pk }}
{% include 'child_template.html' %}
{% endfor %}
child_template.html
Child: {{ item.pk }}
URL: {% url 'detail-view' item.pk %}
I get a reverse error:
Reverse for '/test/url/<int:pk>/' with arguments '('',)' not found. 1 pattern(s) tried: ['test/url/(?P<pk>[0-9]+)/\\Z']
If however I remove the {% url ... %} template tag, it renders correctly and shows:
Parent: 1
Child: 1
So it's clear that item is in the context, but for some reason it isn't being passed to the templatetag.
I have also tried variations like:
{% for item in items %}
{% with new_item=item %}
{% include 'child_template.html' %}
{% endwith %}
{% endfor %}
Any ideas?
I am using Django 3.2.12
I just found the error - I was looking in the wrong place. My complete code looked like this:
parent.html
<!-- {% include 'child_template.html' %} -->
{% for item in items %}
{% with new_item=item %}
{% include 'child_template.html' %}
{% endwith %}
{% endfor %}
I didn't pay attention to the HTML comment at the top of the template. Obviously Django is still rendering the code on the server side and at that point does not have item in its context.

Iterate context variables in Django templates based on user's attributes

Is it possible to iterate over a list of three context variables shown below so that depending on the user's attribute (in this instance grade, Grade 10, Grade 11, Grade 12). If current user's grade attribute is Grade 10 then they only get: context['grade10'] from below.
Current view:
class SumListView(ListView):
model = Summaries
template_name = 'exam/summary.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['grade10'] = Summary.objects.filter(grade='Grade 10')
context['grade11'] = Summary.objects.filter(grade='Grade 11')
context['grade12'] = Summary.objects.filter(grade='Grade 12')
return context'''
Current html template block:
{% block content %}
{% for summary in grade10 %}
<div class="container>
{{ summary.content }}
</div>
{% endfor %}
{% endblock content %}
I tried this but it breaks the code since for loops and iterations are mixing:
{% block content %}
{% if grade10 %}
{% for summary in grade10 %}
<div class="container>
{{ summary.content }}
</div>
{% endfor %}
{% elif grade11 %}
{% for summary in grade10 %}
<div class="container>
{{ summary.content }}
</div>
{% endfor %}
{% else grade12 %}
{% for summary in grade10 %}
<div class="container>
{{ summary.content }}
</div>
{% endfor %}
{% enif %}
{% endblock content %}
What is the best way to go about this?
I know I can write different urls for each context which in turn renders a different template but that does not seem efficient and I hope there is a better way to do that. Any help highly appreciated, including documentation pointers.
You can perform this logic in your view, you can use a single context variable but change it's contents based on your logic
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
user_grade = self.request.user.get_grade() # Replace with how you access the user's grade
context['grades'] = Summary.objects.filter(grade=user_grade)
return context
Then loop over grades in your template

Django simple tag doesn't work in if condition

I want to customize django-admin's change form for video objects by adding block with moderation tools.
When I use custom simpletags in if condition - it doesn't work.
models.py:
class Video(models.Model):
class Meta:
db_table = 'video'
DRAFT = 1
MODERATION = 2
PUBLISHED = 3
REJECTED = 4
HOSTING_UPLOADING = 5
SUSPICIOUS = 6
PUBLICATION_STATUSES = (
(DRAFT, 'draft'),
(MODERATION, 'moderation'),
(PUBLISHED, 'published'),
(HOSTING_UPLOADING, 'hosting uploading'),
(REJECTED, 'rejected'),
(SUSPICIOUS, 'suspicious')
)
video_pk = models.AutoField(primary_key=True)
name = models.CharField(max_length=150, blank=True)
hosting_id = models.CharField(max_length=20, blank=True)
publication_status = models.PositiveSmallIntegerField(choices=PUBLICATION_STATUSES, default=MODERATION)
templatetags video_publication_statuses.py:
from api.models import Video
from django import template
register = template.Library()
#register.simple_tag
def moderation(status):
return status == Video.MODERATION
#register.simple_tag
def suspicious(status):
return status == Video.SUSPICIOUS
#register.simple_tag
def published(status):
return status == Video.PUBLISHED
#register.simple_tag
def hosting_uploading(status):
return status == Video.HOSTING_UPLOADING
#register.simple_tag
def rejected(status):
return status == Video.REJECTED
change_form.html:
{% extends "admin/change_form.html" %}
{% load video_publication_statuses %}
{% suspicious original.publication_status as suspicious_status %}
{% moderation original.publication_status as moderation_status %}
{% hosting_uploading original.publication_status as hosting_uploading_status %}
{% published original.publication_status as published_status %}
{% rejected original.publication_status as rejected_status %}
{% block after_related_objects %}
{% if original.pk %}
{% for fieldset in adminform %}
{% if fieldset.name == 'Moderation' %}
{% include "admin/includes/fieldset.html" %}
{% endif %}
{% endfor %}
<div class="submit-row">
{% if rejected_status or moderation_status or suspicious_status %}
<input type="submit" value="Publish" name="publish" >
{% endif %}
{% if published_status %}
<input type="submit" value="Reject" name="reject" >
{% endif %}
</div>
{% endif %}
{% endblock %}
When I use explicit values instead of tags it works:
{% if original.publication_status == 3 %}
<input type="submit" value="Reject" name="reject" >
{% endif %}
Please help me understand what is wrong with tags?
I believe this is happening because template tags pass strings and you're checking a string against an integer e.g. return "3" == 3
Broadly speaking though, you're putting a lot of logic in a template and I typically avoid that situation. Template tags are reserved for "presentation logic" and I take that to mean "changing the way something is presented", not changing what is viewed. That logic belongs in a view or the model itself.
It should be easy enough to put this logic on your model.
class Original(...):
def rejected(self):
return self.status == Video.rejected

Could not parse the remainder django template

I have a condition within a loop in my template like this:
{% for message in message_trash %}
<td><a href="#">
{% if request.session.user_email == message.message_user_reciever.user_email %}
{{ message.message_user_reciever.user_firstName }} {{ message.message_user_reciever.user_lastName }}
{% elif request.session.user_email == message.message_user_sender.user_email %}
{{ message.message_user_sender.user_firstName }} {{ message.message_user_sender.user_lastName }}
{% endif %}
</a><small>Friends</small></td>
{% endfor %}
but i don't know why i get this error when applying the url?
TemplateSyntaxError: Could not parse the remainder: '==message.message_user_reciever.user_email' from 'request.session.user_email==message.message_user_reciever.user_email'
Update:
this is the view and variables that i render to the template:
def trashMessages(request, userId):
if isMessageOwner(request, userId):
user = Users.objects.get(user_id=userId)
message_trash = Messages.objects.filter(Q(message_user_reciever= user, message_sender_type='TRASH') | Q(message_user_sender=user, message_reciever_type='TRASH'))
return render(request, 'navigation_messages.html', {'user': user, 'message_trash': message_trash, 'type': 'trash'})
On testing your code out, I can only replicate your issue is by swapping:
{% if request.session.user_email == message.message_user_reciever.user_email %}
for
{% if request.session.user_email ==message.message_user_reciever.user_email %}
Note the missing space. Is the snippet in your question exactly as it is in your template?

Get current URL kwargs in the template?

I'm accomplishing this at the moment by doing:
context['card_type'] = self.kwargs['card_type']
context['role_line'] = self.kwargs['role_line']
context['sort_by'] = self.kwargs['sort_by']
Which seems crazy counter intuitive to me.
Say if i was already at the urls of players/one/two/three
Is there an already prebuilt way to get current kwargs of one, two & three for use in templates?
Edit
urls.py
urlpatterns = patterns('',
url(
r'^$',
NationListView.as_view(),
name='index'
),
url(
r'^(?P<slug>[a-z-]*)/$',
NationDetailView.as_view(),
name='nation'
),
url(
r'^(?P<slug>[a-z-]*)/(?P<card_type>[a-z]*)/(?P<role_line>[a-z]*)/(?P<sort_by>[a-z0-9]*)/$',
NationDetailFilteredView.as_view(),
name='nation_filter'
),
)
The mixin that builds the context
class CoreDetailFilteredMixin(object):
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(CoreDetailFilteredMixin, self).get_context_data(**kwargs)
base_objects(context)
# Pull all the players that belong to the object_type
context['players'] = Player.objects.filter(
**{filters: context['object'].asset_id}
)
# Define the available card types
card_types = {
'if': {'card_type__gte': 2},
'gold': {'overall_rating__gte': 75},
'silver': {'overall_rating__range': (65, 74)},
'bronze': {'overall_rating__lte': 64}
}
# Check if the given card type is in the dictionary because 'all' throws an KeyError
if self.kwargs['card_type'] in card_types:
context['players'] = context['players'].filter(**card_types[self.kwargs['card_type']])
# Don't show inform cards for specific colour card types
if self.kwargs['card_type'] not in ['if', 'all']:
context['players'] = context['players'].exclude(card_type__gte=2)
# Define available role lines
role_lines = {
'att': 3,
'mid': 2,
'def': 1,
'gk': 0
}
# Check if the given role line is in the dictionary because 'all' throws an KeyError
if self.kwargs['role_line'] in role_lines:
context['players'] = context['players'].filter(role_line=role_lines[self.kwargs['role_line']])
# Define the available sort by keys
sorts = {
'ovr': 'overall_rating',
'att1': 'card_att1',
'att2': 'card_att2',
'att3': 'card_att3',
'att4': 'card_att4',
'att5': 'card_att5',
'att6': 'card_att6r'
}
# Add a descending order to the existing queryset
context['players'] = context['players'].order_by('-' + sorts[self.kwargs['sort_by']])
# Create pagination
cbv_pagination(self, context, context['players'], 28, 'players')
context['card_type'] = self.kwargs['card_type']
context['role_line'] = self.kwargs['role_line']
context['sort_by'] = self.kwargs['sort_by']
return context
How i use it currently in the template
{% with object.get_class_name|add:'s'|add:':'|add:object.get_class_name|add:'_filter'|lower as url_string %}
<dl class="sub-nav">
<dt>Card Type:</dt>
{% with 'all if gold silver bronze' as card_types %}
{% for ct in card_types.split %}
{% cycle 'All' 'Inform' 'Gold' 'Silver' 'Bronze' as card_type_name silent %}
{% if card_type == ct %}
<dd class="active">
{% else %}
<dd>
{% endif %}
<a href="{% url url_string object.slug ct role_line|default:'all' sort_by|default:'ovr' %}">
{{ card_type_name }}
</a>
</dd>
{% endfor %}
{% endwith %}
</dl>
<dl class="sub-nav">
<dt>Role Line:</dt>
{% with 'all att mid def gk' as role_lines %}
{% for rl in role_lines.split %}
{% cycle 'All' 'Attackers' 'Midfielders' 'Defenders' 'Goalkeepers' as role_lines_name silent %}
{% if role_line == rl %}
<dd class="active">
{% else %}
<dd>
{% endif %}
<a href="{% url url_string object.slug card_type|default:'all' rl sort_by|default:'ovr' %}">
{{ role_lines_name }}
</a>
</dd>
{% endfor %}
{% endwith %}
</dl>
<dl class="sub-nav">
<dt>Sort By:</dt>
{% with 'ovr att1 att2 att3 att4 att5 att6' as sorts %}
{% for sort in sorts.split %}
{% ifequal role_line 'gk' %}
{% cycle 'Overall' 'Diving' 'Handling' 'Kicking' 'Reflexes' 'Speed' 'Positioning' as sorts_name silent %}
{% else %}
{% cycle 'Overall' 'Pace' 'Shooting' 'Passing' 'Dribbling' 'Defending' 'Heading' as sorts_name silent %}
{% endifequal %}
{% if sort_by == sort %}
<dd class="active">
{% else %}
<dd>
{% endif %}
<a href="{% url url_string object.slug card_type|default:'all' role_line|default:'all' sort %}">
{{ sorts_name }}
</a>
</dd>
{% endfor %}
{% endwith %}
</dl>
{% endwith %}
As I learnt here, the view is already passed to the context (for class-based views). So you can do the following in the template without needing to explicitly pass the kwargs from the view:
{{ view.kwargs.card_type }}
{{ view.kwargs.role_line }}
{{ view.kwargs.sort_by }}
You can use dict.update():
update([other])
Update the dictionary with the key/value pairs from other, overwriting existing keys.
context.update(self.kwargs)