Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can i get the object in django admin change_list template

Tags:

python

django

I want to override the django admin change_list page but i am not able to find how to get the actual object so that i can access the proerties like object.name

In the template they have this code

<tr >{% for item in result %}{{ item }}{% endfor %}</tr>

where is the actual object which i can use

EDIT:

It look like result is the row and item is the column. i want something like result.pk

This yield the list if results

https://github.com/django/django/blob/master/django/contrib/admin/templatetags/admin_list.py#L175

like image 844
user2294401 Avatar asked Dec 02 '22 23:12

user2294401


2 Answers

The context fed to change_list.html includes a cl entry corresponding to a contrib.admin.views.main.ChangeList object, which is the object containing the result list.

You can access the result list directly like this:

{% for object in cl.result_list %}
{{ object.field }}
{% endfor %}

The change list results are rendered as part of the change_list_results.html template through use of the result_list template tag. The change_list_results.html template also has the cl context variable present when rendering the template.

When the Django template is iterating over result in your example, result is a ResultList object which contains pre-rendered html, the underlying object which is being rendered is not made available.

To override the template at this level, it's likely you'll need to implement your own result_list type template tag which can return a list of results with the underlying objects attached as an attribute to each result.

In short it is likely that you will need to:

  • Create your own result_list template tag, based on the Django's implementation. Rather than have it return a results context as a list of ResultList prerendered html, have it return results containing objects which are both capable of being rendered to html, as well as each item having the original underlying object attached for later use in your template.
  • Override the change_list.html template to use your new tag rather than Django's result_list template tag.
  • Override the change_list_results.html template to make use of the extra information available from your template tag such as the presence of each underlying object.

As you've probably gathered, the admin app is quite tightly integrated through the layers. Changing its operation is non-trivial and requires changes and overrides in multiple parts of the source.

like image 160
Austin Phillips Avatar answered Dec 09 '22 16:12

Austin Phillips


You can also override template you use for admin with "change_list_template" and then extend change_list template. Like

class NoiseFilter200Admin(admin.ModelAdmin):
    change_list_template = 'currencies/nf200_change_list.html'
    list_filter = ['sectors',]
    search_fields = ['name']
    #list_filter = ( MarketCapFilter )

    def market_cap_value(self, obj):
      return obj.market_cap_value > 1000000000

    def changelist_view(self, request, extra_context=None):
        response = super().changelist_view(
            request,
            extra_context=extra_context,
        )
        try:
            qs = response.context_data['cl'].queryset
        except (AttributeError, KeyError):
            return response

        metrics = {
            'total_volume': Sum('volume'),
            'total_mcap': Sum('market_cap'),
        }
        response.context_data['nf_200_list'] = list(
            qs
            .values('rank','ticker','name','priceUSD','market_cap','volume','change_24h')
           # .annotate(**metrics)
            .order_by('-market_cap')[:200]
        )

        response.context_data['nf_200_totals'] = dict(
            qs.aggregate(**metrics)
        )

        return response

Then in your template you go like this and iterate over results and you will have a look you want

{% extends "admin/change_list.html" %}
{% load humanize %}
{% load math_tags %}

{% block content_title %}
    <h1> Noise Filter 200 </h1>
{% endblock %}
{% block result_list %}
<style>
.results table {
    counter-reset: rowNumber;
}

.results tbody tr{
    counter-increment: rowNumber;
}

.results tbody td.rank::before {
    content: counter(rowNumber);;
}
</style>
    <div style="margin: 10px 0;">Total MCap today: {{ nf_200_totals.total_mcap | intword }}, Total volume today: {{ nf_200_totals.total_volume | intword }} </div>
<div class="results">
    <table>
    <thead>
      <tr>
        <th>
          <div class="text">
            Rank
          </div>
        </th>
        <th>
          <div class="text">
            <a href="#">Name</a>
          </div>
        </th>
        <th>
          <div class="text">
            <a href="#">Ticker</a>
          </div>
        </th>
        <th>
          <div class="text">
            <a href="#">PriceUSD</a>
          </div>
        </th>
        <th>
          <div class="text">
            <a href="#">Market cap</a>
          </div>
        </th>
        <th>
          <div class="text">
            <a href="#">Volume</a>
          </div>
        </th>
        <th>
          <div class="text">
            <a href="#">Change 24</a>
          </div>
        </th>
      </tr>
    </thead>
    <tbody>
      {% for row in nf_200_list %}
      <tr class="{% cycle 'row1' 'row2' %}">
        <td class="rank">  </td>
        <td> {{ row.name }} </td>
        <td> {{ row.ticker }} </td>
        <td> $ {{ row.priceUSD|to_string }} </td>
        <td> {{ row.market_cap | intword }} </td>
        <td> {{ row.volume | intword }} </td>
        <td> {{ row.change_24h | percent}} </td>
      </tr>
      {% endfor %}
    </tbody>

  </table>
</div>
{% endblock %}
{% block pagination %}{% endblock %}

Downside is you may use some functionality here that you get (like sorting).

like image 27
Blissful Avatar answered Dec 09 '22 15:12

Blissful