Last active
February 23, 2020 19:24
-
-
Save dex4er/c658c38c3a12df7b92fc to your computer and use it in GitHub Desktop.
result_list with support for aggregated QuerySet for Django 1.8.4
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{# templates/admin/change_list.html #} | |
{% extends "admin/base_site.html" %} | |
{% load i18n admin_urls admin_static admin_list values_result_list %} | |
{% block extrastyle %} | |
{{ block.super }} | |
<link rel="stylesheet" type="text/css" href="{% static "admin/css/changelists.css" %}" /> | |
{% if cl.formset %} | |
<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}" /> | |
{% endif %} | |
{% if cl.formset or action_form %} | |
<script type="text/javascript" src="{% url 'admin:jsi18n' %}"></script> | |
{% endif %} | |
{{ media.css }} | |
{% if not actions_on_top and not actions_on_bottom %} | |
<style> | |
#changelist table thead th:first-child {width: inherit} | |
</style> | |
{% endif %} | |
{% endblock %} | |
{% block extrahead %} | |
{{ block.super }} | |
{{ media.js }} | |
{% if action_form %}{% if actions_on_top or actions_on_bottom %} | |
<script type="text/javascript"> | |
(function($) { | |
$(document).ready(function($) { | |
$("tr input.action-select").actions(); | |
}); | |
})(django.jQuery); | |
</script> | |
{% endif %}{% endif %} | |
{% endblock %} | |
{% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} change-list{% endblock %} | |
{% if not is_popup %} | |
{% block breadcrumbs %} | |
<div class="breadcrumbs"> | |
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> | |
› <a href="{% url 'admin:app_list' app_label=cl.opts.app_label %}">{{ cl.opts.app_config.verbose_name }}</a> | |
› {{ cl.opts.verbose_name_plural|capfirst }} | |
</div> | |
{% endblock %} | |
{% endif %} | |
{% block coltype %}flex{% endblock %} | |
{% block content %} | |
<div id="content-main"> | |
{% block object-tools %} | |
{% if has_add_permission %} | |
<ul class="object-tools"> | |
{% block object-tools-items %} | |
<li> | |
{% url cl.opts|admin_urlname:'add' as add_url %} | |
<a href="{% add_preserved_filters add_url is_popup to_field %}" class="addlink"> | |
{% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %} | |
</a> | |
</li> | |
{% endblock %} | |
</ul> | |
{% endif %} | |
{% endblock %} | |
{% if cl.formset.errors %} | |
<p class="errornote"> | |
{% if cl.formset.total_error_count == 1 %}{% trans "Please correct the error below." %}{% else %}{% trans "Please correct the errors below." %}{% endif %} | |
</p> | |
{{ cl.formset.non_form_errors }} | |
{% endif %} | |
<div class="module{% if cl.has_filters %} filtered{% endif %}" id="changelist"> | |
{% block search %}{% search_form cl %}{% endblock %} | |
{% block date_hierarchy %}{% date_hierarchy cl %}{% endblock %} | |
{% block filters %} | |
{% if cl.has_filters %} | |
<div id="changelist-filter"> | |
<h2>{% trans 'Filter' %}</h2> | |
{% for spec in cl.filter_specs %}{% admin_list_filter cl spec %}{% endfor %} | |
</div> | |
{% endif %} | |
{% endblock %} | |
<form id="changelist-form" action="" method="post"{% if cl.formset.is_multipart %} enctype="multipart/form-data"{% endif %} novalidate>{% csrf_token %} | |
{% if cl.formset %} | |
<div>{{ cl.formset.management_form }}</div> | |
{% endif %} | |
{% block result_list %} | |
{% if action_form and actions_on_top and cl.show_admin_actions %}{% admin_actions %}{% endif %} | |
{% values_result_list cl %} | |
{% if action_form and actions_on_bottom and cl.show_admin_actions %}{% admin_actions %}{% endif %} | |
{% endblock %} | |
{% block pagination %}{% pagination cl %}{% endblock %} | |
</form> | |
</div> | |
</div> | |
{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# templatetags/values_result_list.py | |
from __future__ import unicode_literals | |
import datetime | |
from django import template | |
from django.contrib.admin.templatetags.admin_list import ( | |
result_headers, result_hidden_fields, ResultList | |
) | |
from django.contrib.admin.templatetags.admin_urls import add_preserved_filters | |
from django.contrib.admin.utils import ( | |
display_for_field, display_for_value, lookup_field | |
) | |
from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE | |
from django.core.exceptions import ObjectDoesNotExist | |
from django.core.urlresolvers import NoReverseMatch | |
from django.db import models | |
from django.utils.encoding import force_text | |
from django.utils.html import escapejs, format_html | |
from django.utils.safestring import mark_safe | |
register = template.Library() | |
def items_for_result(cl, result, form): | |
def link_in_col(is_first, field_name, cl): | |
if cl.list_display_links is None: | |
return False | |
if is_first and not cl.list_display_links: | |
return True | |
return field_name in cl.list_display_links | |
first = True | |
pk = cl.lookup_opts.pk.attname | |
for field_name in cl.list_display: | |
row_classes = ['field-%s' % field_name] | |
try: | |
if isinstance(result, dict): | |
f, attr, value = None, field_name, result[field_name] | |
else: | |
f, attr, value = lookup_field(field_name, result, cl.model_admin) | |
except ObjectDoesNotExist: | |
result_repr = EMPTY_CHANGELIST_VALUE | |
else: | |
if f is None or f.auto_created: | |
if field_name == 'action_checkbox': | |
row_classes = ['action-checkbox'] | |
allow_tags = getattr(attr, 'allow_tags', False) | |
boolean = getattr(attr, 'boolean', False) | |
if boolean: | |
allow_tags = True | |
result_repr = display_for_value(value, boolean) | |
# Strip HTML tags in the resulting text, except if the | |
# function has an "allow_tags" attribute set to True. | |
if allow_tags: | |
result_repr = mark_safe(result_repr) | |
if isinstance(value, (datetime.date, datetime.time)): | |
row_classes.append('nowrap') | |
else: | |
if isinstance(f.rel, models.ManyToOneRel): | |
field_val = getattr(result, f.name) | |
if field_val is None: | |
result_repr = EMPTY_CHANGELIST_VALUE | |
else: | |
result_repr = field_val | |
else: | |
result_repr = display_for_field(value, f) | |
if isinstance(f, (models.DateField, models.TimeField, models.ForeignKey)): | |
row_classes.append('nowrap') | |
if force_text(result_repr) == '': | |
result_repr = mark_safe(' ') | |
row_class = mark_safe(' class="%s"' % ' '.join(row_classes)) | |
# If list_display_links not defined, add the link tag to the first field | |
if link_in_col(first, field_name, cl): | |
table_tag = 'th' if first else 'td' | |
first = False | |
# Display link to the result's change_view if the url exists, else | |
# display just the result's representation. | |
try: | |
url = cl.url_for_result(result) | |
except NoReverseMatch: | |
link_or_text = result_repr | |
else: | |
url = add_preserved_filters({'preserved_filters': cl.preserved_filters, 'opts': cl.opts}, url) | |
# Convert the pk to something that can be used in Javascript. | |
# Problem cases are long ints (23L) and non-ASCII strings. | |
if cl.to_field: | |
attr = str(cl.to_field) | |
else: | |
attr = pk | |
value = result.serializable_value(attr) | |
result_id = escapejs(value) | |
link_or_text = format_html( | |
'<a href="{}"{}>{}</a>', | |
url, | |
format_html( | |
' onclick="opener.dismissRelatedLookupPopup(window, ' | |
''{}'); return false;"', result_id | |
) if cl.is_popup else '', | |
result_repr) | |
yield format_html('<{}{}>{}</{}>', | |
table_tag, | |
row_class, | |
link_or_text, | |
table_tag) | |
else: | |
# By default the fields come from ModelAdmin.list_editable, but if we pull | |
# the fields out of the form instead of list_editable custom admins | |
# can provide fields on a per request basis | |
if (form and field_name in form.fields and not ( | |
field_name == cl.model._meta.pk.name and | |
form[cl.model._meta.pk.name].is_hidden)): | |
bf = form[field_name] | |
result_repr = mark_safe(force_text(bf.errors) + force_text(bf)) | |
yield format_html('<td{}>{}</td>', row_class, result_repr) | |
if form and not form[cl.model._meta.pk.name].is_hidden: | |
yield format_html('<td>{}</td>', force_text(form[cl.model._meta.pk.name])) | |
def results(cl): | |
if cl.formset: | |
for res, form in zip(cl.result_list, cl.formset.forms): | |
yield ResultList(form, items_for_result(cl, res, form)) | |
else: | |
for res in cl.result_list: | |
yield ResultList(None, items_for_result(cl, res, None)) | |
@register.inclusion_tag("admin/change_list_results.html") | |
def values_result_list(cl): | |
headers = list(result_headers(cl)) | |
num_sorted_fields = 0 | |
for h in headers: | |
if h['sortable'] and h['sorted']: | |
num_sorted_fields += 1 | |
return {'cl': cl, | |
'result_hidden_fields': list(result_hidden_fields(cl)), | |
'result_headers': headers, | |
'num_sorted_fields': num_sorted_fields, | |
'results': list(results(cl))} | |
@register.inclusion_tag('admin/change_list_results.html', takes_context=True) | |
def values_result_list_with_context(context, cl): | |
""" | |
Wraps Djangos default result_list to ammend the context with the request. | |
This gives us access to the request in change_list_results. | |
""" | |
res = values_result_list(cl) | |
res['request'] = context['request'] | |
return res |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment