Django templates - Regrouping by a string parameter - django

I have the following code in one of my Django templates that I want to refactor:
{% ifequal sort_type "set" %}
{% regroup cards by set as grouped %}
{% endifequal %}
{% ifequal sort_type "rarity" %}
{% regroup cards by rarity as grouped %}
{% endifequal %}
It does work, but it's really ugly and I want to make it more like this:
{% regroup cards by sort_type as groupedcards %}
But this doesn't work (it just puts them all in a single group called None.) From the documentation, I think it might be trying a dictionary lookup (i.e., calling card["set"] instead of card.set).
Is there a good way to do this in the template, or should I move the regrouping out into the Python code using itertools?

Ticked in Django bugtracker related to this problem.

Related

Double loop with django Templates

so I have this matrix sent to a view
[[6.197, 6.156, 6.165, 6.164, 4.741], [6.191, 6.106, 6.175, 6.132, 4.741], [6.158, 6.137, 6.137, 6.133, 4.741]]
and a list containing dates
["11-12-2016","12-12-2016","13-12-2016"]
and I want to format them with Template to look like this
[["11-12-2016",6.197, 6.156, 6.165, 6.164, 4.741]
["12-12-2016",6.191, 6.106, 6.175, 6.132, 4.741]
....]
Iam using this code :
{% for date in dates %}
{% with forloop.counter0 as i %}
,["{{date}}"{% for item in selling.i %} ,{{item}} {% endfor %}]
{% endwith %}
{% endfor %}
and it doesn't work , but when I replace i with 0,1.. the second loop works fine on one list
{% for item in selling.i %}
This isn't going to work -- the template will look for an attribute or index literally equal to "i", and not the value of that variable.
The Django template language actively discourages using too much logic in the template, and this is an example of something you can't do.
So create the lists as you want them in Python, and pass those to the template. E.g. in Python
combined = [[str(date)] + sell for date, sell in zip(dates, selling)]
And in the template
{% for row in combined %}
[{{ row|join:","|safe }}],
{% endfor %}

Django template - set variable in for loop

I am using this code in my templatetags:
http://pastie.org/3530409
And I know for context problem and bad design (that this logic should not be in view) but I need in template solution for this:
{% for tag in page.tagname_list %}
{% ifequal tag "wiki" %}
{% set howto = 1 %}
{% endifequal %}
{% endfor %}
So I can use howto variable latter for my view logic.
Is there any way to do this in view templates, without model modification ?
If answer yes, please provide some solution...
Thanks a lot.
Instead of having to set the variable, you could just do:
{% if "wiki" in page.tagname_list %}
# do your wiki stuff below.
{% endif %}

Django template for loop. Member before

I want to create such loop:
{% for object in objects %}
{% if object.before != object %}
{{ object }} this is different
{% else %}
{{ object }} this is the same
{% endfor %}
Based on https://docs.djangoproject.com/en/dev/ref/templates/builtins/?from=olddocs#for I can't. Is there really no simple way to do this? Or I just need to use counter and check for objects[counter-1]?
P.S. .before is theoretical and objects is simple query list. I want to take and do something with the loop member that encountered before current loop member.
Check ifchanged template tag
There is a "simple way" to do this: write a custom template tag. They're really not hard. This would probably do the trick (untested):
#register.simple_tag
def compare_objects(object_list):
comparisons = []
for i in range(1, len(object_list)):
if object_list[i] > object_list[i-1]:
comparisons.append('bigger')
else:
comparisons.append('smaller')
return comparisons
The built-in template tags and filters don't make it easy (as of Django 1.4), but it is possible by using the with tag to cache variables and the add, slugify, and slice filters to generate a new list with only one member.
The following example creates a new list whose sole member is the previous member of the forloop:
{% for item in list %}
{% if not forloop.first %}
{% with forloop.counter0|add:"-1" as previous %}
{% with previous|slugify|add:":"|add:previous as subset %}
{% with list|slice:subset as sublist %}
<p>Current item: {{ item }}</p>
<p>Previous item: {{ sublist.0 }}</p>
{% endwith %}
{% endwith %}
{% endwith %}
{% endif %}
{% endfor %}
This isn't an elegant solution, but the django template system has two faults that make this hack unavoidable for those who don't what to write custom tags:
Django template syntax does not allow nested curly parenthesis. Otherwise, we could do this:
{{ list.{{ forloop.counter|add:-1 }} }}
The lookup operator does not accept values stored using with (and perhaps for good reason)
{% with forloop.counter|add:-1 as index %}
{{ list.index }}
{% endwith %}
This code should work just fine as a django template, as long as object has a property or no-argument method called before, and objects is iterable (and '<' is defined).
{% for object in objects %}
{% if object.before < object %}
this is bigger
{% else %}
this is smaller
{% endfor %}

Django - Is there a way to create a variable in the template?

I want to do this:
{% for egg in eggs %}
<p>{{ egg.spam }}</p>
{% if egg.is_cool %}
{% myvariable = egg %} // Possible in any way?
{% endif %}
{% endfor %}
Pardon the JavaScript-style comment (it shows up as a comment on SO)
I think the closest you'll get is the with tag: http://docs.djangoproject.com/en/dev/ref/templates/builtins/#with.
If you're say trying to feature an item in a template, I can imagine doing something like:
<div class="special">
{% with some_list.first as special_item %}
{{ specialitem }}
{% endwith %}
</div>
<div class="everything">
{% for item in some_list %}
{{ item }}
{% endfor %}
</div>
If you want some special logic to determine which one is the special item, I'd add a method to the object (so you end up with: {% with some_collection.my_method as special_item %} above) or determine the special item before passing it to the view. Hope that helps.
Welcome to Django Templates.
This problem is easily solved with one of the earliest snippets posted to DjangoSnippets.com: the Expr tag.
People can argue all day about the separation of logic from the templates, but that ignores that there is business logic, which belongs in the models or views, and presentation logic which belongs only in the templates. If you have a lot of presentation logic you may want to consider using Jinja2 for some or all of your templates. WARNING: although Jinja2 looks a lot like Django's template language, there are incompatibilities with things like Custom Template Tags.
Yes, you can use the with construct:
{% with myvariable as egg %}
do stuf
{% endwith %}
I think it's probably best to do this kind of test-and-set behaviour in the view, not the template. If anything, it'll give you better control over cacheing if/when you need it.

Reusing django templates?

I find django's template language very limiting. Following along with django's DRY principle, I have a template that I'd like to use in many other templates. For example a patient list:
{% for physician in physicians.all %}
{% if physician.service_patients.count %}
<div id="tabs-{{ forloop.counter }}">
{% include "hospitalists/patient_list.html" %}
</div>
{% endif %}
{% endfor %}
The problem is that the patient_list template is expecting a list of patients named patients. How can I rename physician.service_patients to patients before including the template?
Thanks,
Pete
Use the with tag:
{% for physician in physicians.all %}
{% if physician.service_patients.count %}
{% with physician.service_patients as patients %}
<div id="tabs-{{ forloop.counter }}">
{% include "hospitalists/patient_list.html" %}
</div>
{% endwith %}
{% endif %}
{% endfor %}
You might also upgrade to creating a custom tag:
{% for physician in physicians.all %}
{% if physician.service_patients.count %}
{% patient-list physician.service_patients %}
{% endif %}
{% endfor %}
Although custom tags involve writing Python code, there are shortcuts that make it easy to use an existing template file as a tag: Django Inclusion Tags
When you have "functionality" (specifically an if-condition) inside a loop, you have an opportunity to move this into the view function.
First
This construct
{% for physician in physicians.all %}
{% if physician.service_patients.count %}
{% endif %}
{% endfor %}
Is so common that you have several ways to avoid it.
Change your model. Add a patients" method and use it instead of the default query set that you get with a on-to-many relationship. This method of your model has theif service_patients.count` test, removing it from your template.
This eliminates the {% if %} from your template, reducing it to {% for %} and the actual HTML, which cannot easily the eliminated.
Change your view function. Write a few lines of code to create a list of physicians with service_patients instead of a simplistic collection of physicians. This code in your view function has the if service_patients.count test, removing it from your template.
This eliminates the {% if %} from your template, reducing it to a {% for %} and the actual HTML, which cannot easily be eliminated.
The point is to get rid of the {% if %} so that you're simply cutting and pasting the {% for %} and the actual HTML. By keeping your template to just the HTML (which cannot be eliminated), the only overhead is the {% for %}
Second
It appears that you want to reuse an {% include %} construct in slightly different contexts.
It's not at all clear what the problem with this {% include %} file is. It is "expecting a list of patients named patients" seems superficially silly. Fix it, so it expects physician.patients.
Perhaps you want to use this same list twice. Once with a list called 'patients' and once with a list called 'physician.patients'. In this case, consider (a) simplifying or (b) writing a template tag.
It appears that you have a patient list that is sometimes a stand-alone page, and other times is repeated many times on a much more complex page. Repeating a list of details embedded in some longer list is not really the best page design. Django doesn't help you with this because -- frankly -- it's not easy for people to use. Hence option (a) -- consider redesigning this "patient list within a physician" list as too complex.
However, you can always write a template tags to create really complex pages.
Summary
There's a really good reason why the Django template language has limited functionality. All of your functionality should be either an essential feature of your model, or a feature of the current application that uses the model.
Presentation is simply the translation of objects (and querysets) into HTML. Nothing more
As way, you can try to use in quality templating language jinja. It is more flexible.