Django - customize result list - add element ID - django

I would like to override default Admin Panel result list (change_list_results.html) to add ID for each row in <tr>
Default is:
<tbody>
{% for result in results %}
{% if result.form.non_field_errors %}
<tr><td colspan="{{ result|length }}">{{ result.form.non_field_errors }}</td></tr>
{% endif %}
<tr class="{% cycle 'row1' 'row2' %}">{% for item in result %}{{ item }}{% endfor %}</tr>
{% endfor %}
</tbody>
I would like to have:
<tbody>
{% for result in results %}
{% if result.form.non_field_errors %}
<tr><td colspan="{{ result|length }}">{{ result.form.non_field_errors }}</td></tr>
{% endif %}
<tr class="{% cycle 'row1' 'row2' %}" id="{{ ID }}">{% for item in result %}{{ item }}{% endfor %}</tr>
{% endfor %}
</tbody>
What should i put into {{ ID }} to get element ID?

Unfortunately, the 'items' context variable does not hold instance data, it's just a list with html for each column. To achieve what you need you must search for the equivalent item in the 'cl.result_list' context variable, based on the forloop counter:
<tr class="{% cycle 'row1' 'row2' %}" id="{% with i=forloop.counter0|stringformat:"s"|add:":" %}{% with items=cl.result_list|slice:i %}{{ items.0.pk }}{% endwith %}{% endwith %}">{% for item in result %}{{ item }}{% endfor %}</tr>
Alternatively, if you don't like all these 'with' tags you could create a custom template to get the item from "cl.result_list" directly from the counter index.

I'd guess {{ result.form.instance.id }} judging by the fact there is a result.form attached to a list of results.
Just deductive reasoning. Let me know if it's wrong.

Related

overriding Django change_list_results

I am customizing my admin panel a little and want to add an additional column to it, so as per the docs I have to override the change_form_results.html file but how do I do it? all I see is this code in it
<tbody>
{% for result in results %}
{% if result.form and result.form.non_field_errors %}
<tr><td colspan="{{ result|length }}">{{ result.form.non_field_errors }}</td> </tr>
{% endif %}
<tr>{% for item in result %}
{{ item }}
{% endfor %}</tr>
{% endfor %}
</tbody>
what change am i suppose to make to above code

Django 2.2 How to disable checkboxes in list view

Django 2.2
I have a list view controlled by admin.py class. No custom template, all default. I can control what fields from the table should be shown in the view with this:
fields = ('myfield1','myfield2', ...).
Each row in the list table has a checkbox in the first column, the source looks like this:
<td class="action-checkbox">
<input type="checkbox" name="_selected_action" value="123" class="action-select">
</td>
My questions are:
How to disable those checkboxes (preferably, from Django code, without introducing a custom template) ?
Can it be done for SOME of the checkboxes (let's say I have a list of pk ids for the rows I don't want to see checkboxes.)
You can delete Items with those CheckBoxes, but if you want to customize your own admin page to override it
You can use this doc https://docs.djangoproject.com/en/3.0/ref/contrib/admin/#admin-overriding-templates
This question is 2 years old now, but for the case someone still needs it, the following code works to overwrite the change-list_results.html:
{% load i18n static %}
{% if result_hidden_fields %}
<div class="hiddenfields">{# DIV for HTML validation #}
{% for item in result_hidden_fields %}{{ item }}{% endfor %}
</div>
{% endif %}
{% if results %}
<div class="results">
<table id="result_list">
<thead>
<tr>
{% for header in result_headers %}
{% if "checkbox" in header.text %}
{% else %}
<th scope="col" {{ header.class_attrib }}>
{% if header.sortable %}
{% if header.sort_priority > 0 %}
<div class="sortoptions">
<a class="sortremove" href="{{ header.url_remove }}" title="{% translate "Remove from sorting" %}"></a>
{% if num_sorted_fields > 1 %}<span class="sortpriority" title="{% blocktranslate with priority_number=header.sort_priority %}Sorting priority: {{ priority_number }}{% endblocktranslate %}">{{ header.sort_priority }}</span>{% endif %}
</div>
{% endif %}
{% endif %}
<div class="text">{% if header.sortable %}{{ header.text|capfirst }}{% else %}<span>{{ header.text|capfirst }}</span>{% endif %}</div>
<div class="clear"></div>
{% endif %}
</th>{% endfor %}
</tr>
</thead>
<tbody>
{% for result in results %}
{% if result.form and result.form.non_field_errors %}
<tr><td colspan="{{ result|length }}">{{ result.form.non_field_errors }}</td></tr>
{% endif %}
<tr>
{% for item in result %}
{% if "_selected_action" in item %}
{% else %}
{{ item }}
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
It stops stops the output of the for loops if theres a checkbox in there. --> It just removes the checkboxes.

Displaying label on first form of Django formset only

This is a super straightforward question but I can't seem to find any concise answer it. I have a Django formset that displays different tags associated with an object. Here is the form:
class TagForm(forms.Form):
def __init__(self, *args, **kwargs):
tags = kwargs.pop('tags')
super(TagForm, self).__init__(*args, **kwargs)
self.fields['tags'] = forms.ChoiceField(choices=[(tag, tag) for tag in tags], label="Tags")
I'm rendering the formset using the following code:
<li class="list-group-item">
<ul class="list-inline" id="tag-group">
{{ tag_formset.management_form }}
{% for tag_form in tag_formset %}
<li class="list-inline-item">
{{ tag_form.tags.label_tag }}
{{ tag_form.tags }}
</li>
{% endfor %}
</ul>
</li>
My problem is that this creates a label for each tag. Since this is an inline list, I'd only like to display the label prior to the first tag (and no others). I can't find any straightforward way to do this (without modifying the for loop with explicit logic checking if it is the first form being rendered). I optimistically tried to modify my rendering code to the following:
<li class="list-group-item">
<ul class="list-inline" id="tag-group">
{{ tag_formset.management_form }}
{{ tag_form.empty_form.label_tag }}
{% for tag_form in tag_formset %}
<li class="list-inline-item">
{{ tag_form.tags }}
</li>
{% endfor %}
</ul>
</li>
but this didn't display any labels at all. Is there an idiomatic way to only display the form label prior to the first form in a formset?
The code below is working for me. The main idea is simple. Make a Table and in the headers put the tags. and in the table body put only the data. Try it and let me know.
{% for f1 in formset %}
{{ f1.management_form|crispy }}
{% crispy f1 %}
{% endcomment %}
<table{% if form_id %} id="{{ form_id }}_table" {% endif%} class="table table-striped table-condensed">
<thead>
{% if formset.readonly and not formset.queryset.exists %}
{% else %}
<tr>
<td>
</td>
{% for field in formset.forms.0 %}
{% if field.label and not field.is_hidden %}
<th for="{{ field.auto_id }}"
class="control-label {% if field.field.required %}requiredField{% endif %}">
{{ field.label|safe }}{% if field.field.required %}<span
class="asteriskField">*</span>{% endif %}
</th>
{% endif %}
{% endfor %}
</tr>
{% endif %}
</thead>
<tbody>
{% comment %} <tr class="hidden empty-form">
{% for field in formset.empty_form %}
{% include 'bootstrap/field.html' with tag="td" form_show_labels=False %}
{% endfor %}
</tr> {% endcomment %}
{% for form2 in formset2 %}
{% if form2_show_errors and not form2.is_extra %}
{% include "bootstrap/errors.html" %}
{% endif %}
<tr>
<td>
<a class="btn btn-info pull-right" {% comment %}
href="{% url 'set_final' formfs.pk %}/?next={% url 'update-well-view' form.pk %}">
{% endcomment %}
href="{% url 'Scouts-home' %}"> Set Final
</a>
</td>
{% for field in form2 %}
{% include 'bootstrap/field.html' with tag="td" form2_show_labels=False %}
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>

No named cycles in template. 'row1,row2' is not defined

In my django inline formset, form html:
{% block body %}
<h2>Profile</h2>
<hr>
<div class="col-md-4">
<form action="" method="post">{% csrf_token %}
{{ form.as_p }}
<table class="table">
{{ familymembers.management_form }}
{% for form in familymembers.forms %}
{% if forloop.first %}
<thead>
<tr>
{% for field in form.visible_fields %}
<th>{{ field.label|capfirst }}</th>
{% endfor %}
</tr>
</thead>
{% endif %}
<tr class="{% cycle row1,row2 %} formset_row">
{% for field in form.visible_fields %}
<td>
{# Include the hidden fields in the form #}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{{ field.errors.as_ul }}
{{ field }}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
<input type="submit" value="Save"/> back to the list
</form>
</div>
{% endblock %}
When I tried to open form it gives
TemplateSyntaxError at /profile/add/
No named cycles in template. 'row1,row2' is not defined
How could I avoid this error?
That's not how you use that tag, as the docs show. The values should be separated by spaces, not commas, and if they are literal strings they should be in quotes.
{% cycle "row1" "row2" %}
If you still get an error, you can try:
class="{% cycle 'row1' 'row2' %} formset_row"

django template table rows do not collapse

I can not work-out what I am doing wrong with collapsing certain rows of my table.
Can you advice how can I correct it so I can collapse rows marked in red ?
I guess I have placed collapse tag in wrong place or have not used again ? However can I use table in table ?
my template:
{% extends "base.html" %}
{% block content %}
<h3>{% for project in projects %}{{ project.project_name }}{% endfor %}</h3>
<table class="table table-striped table table-bordered table table-hover table table-condensed">
<tr>
<td></td>
<!-- row with zone names -->
{% for z in zones %}
<td style="width:40px" align="center">{{ z.zone_name }}</td>
{% endfor %}
</tr>
<!-- rows with stage names -->
{% for trstage in trstages %}
<tr>
<td style="width:40px"><a data-toggle="collapse" href="#collapse{{ trstage }}">{{ trstage.stage_name }}</a></td>
<!-- row with stage value -->
{% for stage in trstage.stages %}
{% for zone in zones|dictsort:"zone_name" %}
{% if zone == stage.zone %}
<td style="width:40px" align="center">{{ stage.substage_sum.sum }}</td>
{% endif %}
{% endfor %}
{% endfor %}
</tr>
<div id="collapse{{ trstage }}" class="panel-collapse collapse">
<!-- rows with substages names -->
{% for trsubstage in trstage.related_trsubstages %}
<tr>
<td>{{ trsubstage.substage_name }}</td>
<!-- row with substage value -->
{% for substage in trsubstage.substages_related %}
{% for zone in zones %}
{% if zone == substage.stage.zone %}
<td style="width:40px" align="center">{{ substage.substage_value }}</td>
{% endif %}
{% endfor %}
{% endfor %}
</tr>
{% endfor %}
</div>
{% endfor %}
</table>
{% endblock %}
Below is link to my current template view:
Try adding the id of your trstage to the href and id of the divs. I did something similar in my project and it worked. I hope it works for you too. Like this,
<div id="{{ trstage.id.value }}" class="panel-collapse collapse">
and
<a data-toggle="collapse" href="#{{ trstage.id.value }}">{{ trstage.stage_name }}