chore: cleanup and add support for Python 3.9

master
Kamil Gałuszka 2021-07-17 01:05:59 +02:00
parent b56ded8f0f
commit 51f850f04b
10 changed files with 58 additions and 229 deletions

View File

@ -3,22 +3,18 @@ arch:
- ppc64le - ppc64le
language: python language: python
python: python:
- "3.5"
- "3.6" - "3.6"
- "3.7" - "3.7"
- "3.8" - "3.8"
- "3.9"
env: env:
- DJANGO_VERSION=2.2 SAMPLE_PROJECT=sample_project - DJANGO_VERSION=2.2 SAMPLE_PROJECT=sample_project
- DJANGO_VERSION=3.0 SAMPLE_PROJECT=sample_project - DJANGO_VERSION=3.1 SAMPLE_PROJECT=sample_project
- DJANGO_VERSION=3.2 SAMPLE_PROJECT=sample_project
branches: branches:
only: only:
- develop - develop
matrix:
exclude:
-
python: "3.5"
env: DJANGO_VERSION=3.0 SAMPLE_PROJECT=sample_project
install: install:
- pip install django==$DJANGO_VERSION - pip install django==$DJANGO_VERSION

View File

@ -1,4 +1,4 @@
VERSION = (2, 2, 3) VERSION = (2, 2, 4)
DEV_N = None DEV_N = None

View File

@ -1,10 +1,8 @@
import json import json
from urllib.parse import urlencode from urllib.parse import urlencode
from django import VERSION
from django.conf import settings from django.conf import settings
from django.conf.urls import url from django.conf.urls import re_path
from django.contrib.admin import ModelAdmin, TabularInline, StackedInline from django.contrib.admin import ModelAdmin, TabularInline, StackedInline
from django.contrib.admin.options import InlineModelAdmin from django.contrib.admin.options import InlineModelAdmin
from django.contrib.admin.views.main import IGNORED_PARAMS, PAGE_VAR from django.contrib.admin.views.main import IGNORED_PARAMS, PAGE_VAR
@ -13,7 +11,7 @@ from django.contrib.contenttypes.admin import (GenericStackedInline,
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.db import transaction from django.db import transaction
from django.http import HttpResponse, HttpResponseBadRequest from django.http import JsonResponse
from django.shortcuts import render from django.shortcuts import render
from django.template.defaultfilters import capfirst from django.template.defaultfilters import capfirst
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
@ -116,13 +114,13 @@ class SortableAdmin(SortableAdminBase, ModelAdmin):
info = self.model._meta.app_label, self.model._meta.model_name info = self.model._meta.app_label, self.model._meta.model_name
# this ajax view changes the order of instances of the model type # this ajax view changes the order of instances of the model type
admin_do_sorting_url = url( admin_do_sorting_url = re_path(
r'^sort/do-sorting/(?P<model_type_id>\d+)/$', r'^sort/do-sorting/(?P<model_type_id>\d+)/$',
self.admin_site.admin_view(self.do_sorting_view), self.admin_site.admin_view(self.do_sorting_view),
name='%s_%s_do_sorting' % info) name='%s_%s_do_sorting' % info)
# this view displays the sortable objects # this view displays the sortable objects
admin_sort_url = url( admin_sort_url = re_path(
r'^sort/$', r'^sort/$',
self.admin_site.admin_view(self.sort_view), self.admin_site.admin_view(self.sort_view),
name='%s_%s_sort' % info) name='%s_%s_sort' % info)
@ -163,8 +161,7 @@ class SortableAdmin(SortableAdminBase, ModelAdmin):
opts = self.model._meta opts = self.model._meta
jquery_lib_path = 'admin/js/jquery.js' if VERSION < (1, 9) \ jquery_lib_path = 'admin/js/vendor/jquery/jquery.js'
else 'admin/js/vendor/jquery/jquery.js'
# Determine if we need to regroup objects relative to a # Determine if we need to regroup objects relative to a
# foreign key specified on the model class that is extending Sortable. # foreign key specified on the model class that is extending Sortable.
@ -179,23 +176,13 @@ class SortableAdmin(SortableAdminBase, ModelAdmin):
for field in self.model._meta.fields: for field in self.model._meta.fields:
if isinstance(field, SortableForeignKey): if isinstance(field, SortableForeignKey):
try:
sortable_by_fk = field.remote_field.model sortable_by_fk = field.remote_field.model
except AttributeError:
# Django < 1.9
sortable_by_fk = field.rel.to
sortable_by_field_name = field.name.lower() sortable_by_field_name = field.name.lower()
sortable_by_class_is_sortable = \ sortable_by_class_is_sortable = \
isinstance(sortable_by_fk, SortableMixin) and \ isinstance(sortable_by_fk, SortableMixin) and \
sortable_by_fk.objects.count() >= 2 sortable_by_fk.objects.count() >= 2
if sortable_by_property: if sortable_by_property:
# backwards compatibility for < 1.1.1, where sortable_by was a
# classmethod instead of a property
try:
sortable_by_class, sortable_by_expression = \
sortable_by_property()
except (TypeError, ValueError):
sortable_by_class = self.model.sortable_by sortable_by_class = self.model.sortable_by
sortable_by_expression = sortable_by_class.__name__.lower() sortable_by_expression = sortable_by_class.__name__.lower()
@ -234,9 +221,6 @@ class SortableAdmin(SortableAdminBase, ModelAdmin):
except AttributeError: except AttributeError:
verbose_name_plural = opts.verbose_name_plural verbose_name_plural = opts.verbose_name_plural
if VERSION <= (1, 7):
context = {}
else:
context = self.admin_site.each_context(request) context = self.admin_site.each_context(request)
filters = urlencode(self.get_querystring_filters(request)) filters = urlencode(self.get_querystring_filters(request))
@ -297,7 +281,7 @@ class SortableAdmin(SortableAdminBase, ModelAdmin):
response = {'objects_sorted': False} response = {'objects_sorted': False}
if request.is_ajax(): if request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest':
klass = ContentType.objects.get(id=model_type_id).model_class() klass = ContentType.objects.get(id=model_type_id).model_class()
indexes = [str(idx) for idx in request.POST.get('indexes', []).split(',')] indexes = [str(idx) for idx in request.POST.get('indexes', []).split(',')]
@ -311,25 +295,15 @@ class SortableAdmin(SortableAdminBase, ModelAdmin):
qs = klass.objects.select_for_update().filter(**filters) qs = klass.objects.select_for_update().filter(**filters)
with transaction.atomic(): with transaction.atomic():
objects_dict = {str(obj.pk): obj for obj in qs}
# Python 3.6+ only objects_list = [*objects_dict.keys()]
# objects_dict = {str(obj.pk): obj for obj in qs}
# objects_list = list(objects_dict.keys())
objects_dict = {}
objects_list = []
for obj in qs:
key = str(obj.pk)
objects_dict[key] = obj
objects_list.append(key)
if len(indexes) != len(objects_dict): if len(indexes) != len(objects_dict):
return HttpResponseBadRequest( return JsonResponse({
json.dumps({
'objects_sorted': False, 'objects_sorted': False,
'reason': _("An object has been added or removed " 'reason': _("An object has been added or removed "
"since the last load. Please refresh " "since the last load. Please refresh "
"the page and try reordering again."), "the page and try reordering again."),
}, ensure_ascii=False), }, status_code=400)
content_type='application/json')
order_field_name = klass._meta.ordering[0] order_field_name = klass._meta.ordering[0]
if order_field_name.startswith('-'): if order_field_name.startswith('-'):
@ -357,8 +331,7 @@ class SortableAdmin(SortableAdminBase, ModelAdmin):
self.after_sorting() self.after_sorting()
return HttpResponse(json.dumps(response, ensure_ascii=False), return JsonResponse(response)
content_type='application/json')
class NonSortableParentAdmin(SortableAdmin): class NonSortableParentAdmin(SortableAdmin):
@ -387,31 +360,19 @@ class SortableInlineBase(SortableAdminBase, InlineModelAdmin):
class SortableTabularInline(TabularInline, SortableInlineBase): class SortableTabularInline(TabularInline, SortableInlineBase):
"""Custom template that enables sorting for tabular inlines""" """Custom template that enables sorting for tabular inlines"""
if VERSION >= (2, 0):
template = 'adminsortable/edit_inline/tabular-1.10.x.html'
else:
template = 'adminsortable/edit_inline/tabular.html' template = 'adminsortable/edit_inline/tabular.html'
class SortableStackedInline(StackedInline, SortableInlineBase): class SortableStackedInline(StackedInline, SortableInlineBase):
"""Custom template that enables sorting for stacked inlines""" """Custom template that enables sorting for stacked inlines"""
if VERSION >= (2, 0):
template = 'adminsortable/edit_inline/stacked-1.10.x.html'
else:
template = 'adminsortable/edit_inline/stacked.html' template = 'adminsortable/edit_inline/stacked.html'
class SortableGenericTabularInline(GenericTabularInline, SortableInlineBase): class SortableGenericTabularInline(GenericTabularInline, SortableInlineBase):
"""Custom template that enables sorting for tabular inlines""" """Custom template that enables sorting for tabular inlines"""
if VERSION >= (2, 0):
template = 'adminsortable/edit_inline/tabular-1.10.x.html'
else:
template = 'adminsortable/edit_inline/tabular.html' template = 'adminsortable/edit_inline/tabular.html'
class SortableGenericStackedInline(GenericStackedInline, SortableInlineBase): class SortableGenericStackedInline(GenericStackedInline, SortableInlineBase):
"""Custom template that enables sorting for stacked inlines""" """Custom template that enables sorting for stacked inlines"""
if VERSION >= (2, 0):
template = 'adminsortable/edit_inline/stacked-1.10.x.html'
else:
template = 'adminsortable/edit_inline/stacked.html' template = 'adminsortable/edit_inline/stacked.html'

View File

@ -1,34 +0,0 @@
{% load i18n admin_urls static %}
<div class="js-inline-admin-formset inline-group"
id="{{ inline_admin_formset.formset.prefix }}-group"
data-inline-type="stacked"
data-inline-formset="{{ inline_admin_formset.inline_formset_data }}">
<fieldset class="module {{ inline_admin_formset.classes }}">
<h2>{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}</h2>
{{ inline_admin_formset.formset.management_form }}
{{ inline_admin_formset.formset.non_form_errors }}
{% for inline_admin_form in inline_admin_formset %}<div class="inline-related{% if inline_admin_form.original or inline_admin_form.show_url %} has_original{% endif %}{% if forloop.last %} empty-form last-related{% endif %}" id="{{ inline_admin_formset.formset.prefix }}-{% if not forloop.last %}{{ forloop.counter0 }}{% else %}empty{% endif %}">
<h3>
{% if inline_admin_form.original %}
{% with initial_forms_count=inline_admin_formset.formset.management_form.INITIAL_FORMS.value %}
<i class="fa fa-{% if forloop.first %}sort-desc{% elif forloop.counter == initial_forms_count %}sort-asc{% else %}sort{% endif %}"></i>
{% endwith %}
{% endif %}
<b>{{ inline_admin_formset.opts.verbose_name|capfirst }}:</b>&nbsp;<span class="inline_label">{% if inline_admin_form.original %}{{ inline_admin_form.original }}{% if inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %} <a href="{% url inline_admin_form.model_admin.opts|admin_urlname:'change' inline_admin_form.original.pk|admin_urlquote %}" class="inlinechangelink">{% trans "Change" %}</a>{% endif %}
{% else %}#{{ forloop.counter }}{% endif %}</span>
{% if inline_admin_form.show_url %}<a href="{{ inline_admin_form.absolute_url }}">{% trans "View on site" %}</a>{% endif %}
{% if inline_admin_formset.formset.can_delete and inline_admin_form.original %}<span class="delete">{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}</span>{% endif %}
</h3>
{% if inline_admin_form.form.non_field_errors %}{{ inline_admin_form.form.non_field_errors }}{% endif %}
{% for fieldset in inline_admin_form %}
{% include "admin/includes/fieldset.html" %}
{% endfor %}
{% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
{{ inline_admin_form.fk_field.field }}
{% if inline_admin_form.original %}
<input type="hidden" name="admin_sorting_url" value="{% url opts|admin_urlname:'do_sorting' inline_admin_form.original.model_type_id %}" />
{% endif %}
</div>{% endfor %}
</fieldset>
</div>

View File

@ -1,41 +1,34 @@
{% load i18n admin_urls static django_template_additions %} {% load i18n admin_urls static %}
{% get_django_version as django_version %} <div class="js-inline-admin-formset inline-group"
<div class="inline-group" id="{{ inline_admin_formset.formset.prefix }}-group"> id="{{ inline_admin_formset.formset.prefix }}-group"
<h2>{{ inline_admin_formset.opts.verbose_name_plural|title }} {% if inline_admin_formset.formset.initial_form_count > 1 %} - {% trans "drag and drop to change order" %}{% endif %}</h2> data-inline-type="stacked"
data-inline-formset="{{ inline_admin_formset.inline_formset_data }}">
<fieldset class="module {{ inline_admin_formset.classes }}">
<h2>{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}</h2>
{{ inline_admin_formset.formset.management_form }} {{ inline_admin_formset.formset.management_form }}
{{ inline_admin_formset.formset.non_form_errors }} {{ inline_admin_formset.formset.non_form_errors }}
{% for inline_admin_form in inline_admin_formset %}<div class="inline-related {% if django_version.major >= 1 and django_version.minor >= 9 %}flat-admin{% endif %} {% if forloop.last %} empty-form last-related{% endif %} {% if inline_admin_form.original %} has_original{% endif %}" id="{{ inline_admin_formset.formset.prefix }}-{% if not forloop.last %}{{ forloop.counter0 }}{% else %}empty{% endif %}"> {% for inline_admin_form in inline_admin_formset %}<div class="inline-related{% if inline_admin_form.original or inline_admin_form.show_url %} has_original{% endif %}{% if forloop.last %} empty-form last-related{% endif %}" id="{{ inline_admin_formset.formset.prefix }}-{% if not forloop.last %}{{ forloop.counter0 }}{% else %}empty{% endif %}">
<h3> <h3>
{% if inline_admin_form.original %} {% if inline_admin_form.original %}
{% with initial_forms_count=inline_admin_formset.formset.management_form.INITIAL_FORMS.value %} {% with initial_forms_count=inline_admin_formset.formset.management_form.INITIAL_FORMS.value %}
<i class="fa fa-{% if forloop.first %}sort-desc{% elif forloop.counter == initial_forms_count %}sort-asc{% else %}sort{% endif %}"></i> <i class="fa fa-{% if forloop.first %}sort-desc{% elif forloop.counter == initial_forms_count %}sort-asc{% else %}sort{% endif %}"></i>
{% endwith %} {% endwith %}
{% endif %} {% endif %}
<b>{{ inline_admin_formset.opts.verbose_name|title }}:</b>&nbsp;<span class="inline_label">{% if inline_admin_form.original %}{{ inline_admin_form.original }}{% if inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %} <a href="{% url inline_admin_form.model_admin.opts|admin_urlname:'change' inline_admin_form.original.pk|admin_urlquote %}" class="inlinechangelink">{% trans "Change" %}</a>{% endif %} <b>{{ inline_admin_formset.opts.verbose_name|capfirst }}:</b>&nbsp;<span class="inline_label">{% if inline_admin_form.original %}{{ inline_admin_form.original }}{% if inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %} <a href="{% url inline_admin_form.model_admin.opts|admin_urlname:'change' inline_admin_form.original.pk|admin_urlquote %}" class="inlinechangelink">{% trans "Change" %}</a>{% endif %}
{% else %}#{{ forloop.counter }}{% endif %}</span> {% else %}#{{ forloop.counter }}{% endif %}</span>
{% if inline_admin_form.show_url %}<a href="{% url 'admin:view_on_site' inline_admin_form.original_content_type_id inline_admin_form.original.pk %}">{% trans "View on site" %}</a>{% endif %} {% if inline_admin_form.show_url %}<a href="{{ inline_admin_form.absolute_url }}">{% trans "View on site" %}</a>{% endif %}
{% if inline_admin_formset.formset.can_delete and inline_admin_form.original %}<span class="delete">{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}</span>{% endif %} {% if inline_admin_formset.formset.can_delete and inline_admin_form.original %}<span class="delete">{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}</span>{% endif %}
</h3> </h3>
{% if inline_admin_form.form.non_field_errors %}{{ inline_admin_form.form.non_field_errors }}{% endif %} {% if inline_admin_form.form.non_field_errors %}{{ inline_admin_form.form.non_field_errors }}{% endif %}
{% for fieldset in inline_admin_form %} {% for fieldset in inline_admin_form %}
{% include "admin/includes/fieldset.html" %} {% include "admin/includes/fieldset.html" %}
{% endfor %} {% endfor %}
{% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
{{ inline_admin_form.fk_field.field }}
{% if inline_admin_form.original %} {% if inline_admin_form.original %}
<input type="hidden" name="admin_sorting_url" value="{% url opts|admin_urlname:'do_sorting' inline_admin_form.original.model_type_id %}" /> <input type="hidden" name="admin_sorting_url" value="{% url opts|admin_urlname:'do_sorting' inline_admin_form.original.model_type_id %}" />
{% endif %} {% endif %}
{% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
{{ inline_admin_form.fk_field.field }}
</div>{% endfor %} </div>{% endfor %}
</fieldset>
</div> </div>
<script type="text/javascript">
(function($) {
$("#{{ inline_admin_formset.formset.prefix }}-group .inline-related").stackedFormset({
prefix: '{{ inline_admin_formset.formset.prefix }}',
adminStaticPrefix: '{% static "admin/" %}',
deleteText: "{% trans "Remove" %}",
addText: "{% blocktrans with verbose_name=inline_admin_formset.opts.verbose_name|title %}Add another {{ verbose_name }}{% endblocktrans %}"
});
})(django.jQuery);
</script>

View File

@ -1,81 +0,0 @@
{% load i18n admin_urls static admin_modify django_template_additions %}
<div class="js-inline-admin-formset inline-group" id="{{ inline_admin_formset.formset.prefix }}-group"
data-inline-type="tabular"
data-inline-formset="{{ inline_admin_formset.inline_formset_data }}">
<div class="tabular inline-related {% if forloop.last %}last-related{% endif %}">
{{ inline_admin_formset.formset.management_form }}
<fieldset class="module {{ inline_admin_formset.classes }}">
<h2>{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}</h2>
{{ inline_admin_formset.formset.non_form_errors }}
<table>
<thead><tr>
<th class="original"></th>
{% for field in inline_admin_formset.fields %}
{% if not field.widget.is_hidden %}
<th{% if field.required %} class="required"{% endif %}>{{ field.label|capfirst }}
{% if field.help_text %}&nbsp;<img src="{% static "admin/img/icon-unknown.svg" %}" class="help help-tooltip" width="10" height="10" alt="({{ field.help_text|striptags }})" title="{{ field.help_text|striptags }}" />{% endif %}
</th>
{% endif %}
{% endfor %}
{% if inline_admin_formset.formset.can_delete %}<th>{% trans "Delete?" %}</th>{% endif %}
</tr></thead>
<tbody>
{% for inline_admin_form in inline_admin_formset %}
{% if inline_admin_form.form.non_field_errors %}
<tr><td colspan="{{ inline_admin_form|cell_count }}">{{ inline_admin_form.form.non_field_errors }}</td></tr>
{% endif %}
<tr class="form-row {% cycle "row1" "row2" %} {% if inline_admin_form.original or inline_admin_form.show_url %}has_original{% endif %}{% if forloop.last %} empty-form{% endif %}"
id="{{ inline_admin_formset.formset.prefix }}-{% if not forloop.last %}{{ forloop.counter0 }}{% else %}empty{% endif %}">
<td class="original">
{% if inline_admin_form.original or inline_admin_form.show_url %}<p>
{% with initial_forms_count=inline_admin_form.formset.management_form.INITIAL_FORMS.value %}
<i class="fa fa-{% if forloop.first %}sort-desc{% elif forloop.counter == initial_forms_count %}sort-asc{% else %}sort{% endif %}"></i>
{% endwith %}
{% if inline_admin_form.original %}
{{ inline_admin_form.original }}
{% if inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %}<a href="{% url inline_admin_form.model_admin.opts|admin_urlname:'change' inline_admin_form.original.pk|admin_urlquote %}" class="inlinechangelink">{% trans "Change" %}</a>{% endif %}
{% endif %}
{% if inline_admin_form.show_url %}<a href="{{ inline_admin_form.absolute_url }}">{% trans "View on site" %}</a>{% endif %}
</p>{% endif %}
{% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
{{ inline_admin_form.fk_field.field }}
{% spaceless %}
{% for fieldset in inline_admin_form %}
{% for line in fieldset %}
{% for field in line %}
{% if field.field.is_hidden %} {{ field.field }} {% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endspaceless %}
{% if inline_admin_form.original %}
<input type="hidden" name="admin_sorting_url" value="{% url opts|admin_urlname:'do_sorting' inline_admin_form.original.model_type_id %}" />
{% endif %}
</td>
{% for fieldset in inline_admin_form %}
{% for line in fieldset %}
{% for field in line %}
{% if not field.field.is_hidden %}
<td{% if field.field.name %} class="field-{{ field.field.name }}"{% endif %}>
{% if field.is_readonly %}
<p>{{ field.contents }}</p>
{% else %}
{{ field.field.errors.as_ul }}
{{ field.field }}
{% endif %}
</td>
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% if inline_admin_formset.formset.can_delete %}
<td class="delete">{% if inline_admin_form.original %}{{ inline_admin_form.deletion_field.field }}{% endif %}</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</fieldset>
</div>
</div>

View File

@ -1,17 +1,19 @@
{% load i18n admin_urls static admin_modify django_template_additions %}{% load cycle from future %} {% load i18n admin_urls static admin_modify django_template_additions %}
{% get_django_version as django_version %} <div class="js-inline-admin-formset inline-group" id="{{ inline_admin_formset.formset.prefix }}-group"
<div class="inline-group {% if django_version.major >= 1 and django_version.minor >= 9 %}flat-admin{% endif %}" id="{{ inline_admin_formset.formset.prefix }}-group"> data-inline-type="tabular"
data-inline-formset="{{ inline_admin_formset.inline_formset_data }}">
<div class="tabular inline-related {% if forloop.last %}last-related{% endif %}"> <div class="tabular inline-related {% if forloop.last %}last-related{% endif %}">
{{ inline_admin_formset.formset.management_form }} {{ inline_admin_formset.formset.management_form }}
<fieldset class="module"> <fieldset class="module {{ inline_admin_formset.classes }}">
<h2>{{ inline_admin_formset.opts.verbose_name_plural|capfirst }} {% if inline_admin_formset.formset.initial_form_count > 1 %} - {% trans "drag and drop to change order" %}{% endif %}</h2> <h2>{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}</h2>
{{ inline_admin_formset.formset.non_form_errors }} {{ inline_admin_formset.formset.non_form_errors }}
<table> <table>
<thead><tr> <thead><tr>
<th class="original"></th>
{% for field in inline_admin_formset.fields %} {% for field in inline_admin_formset.fields %}
{% if not field.widget.is_hidden %} {% if not field.widget.is_hidden %}
<th{% if forloop.first %} colspan="2"{% endif %}{% if field.required %} class="required"{% endif %}>{{ field.label|capfirst }} <th{% if field.required %} class="required"{% endif %}>{{ field.label|capfirst }}
{% if field.help_text %}&nbsp;<img src="{% if django_version.major >= 1 and django_version.minor >= 9 %}{% static "admin/img/icon-unknown.svg" %}{% else %}{% static "admin/img/icon-unknown.gif" %}{% endif %}" class="help help-tooltip" width="10" height="10" alt="({{ field.help_text|striptags }})" title="{{ field.help_text|striptags }}" />{% endif %} {% if field.help_text %}&nbsp;<img src="{% static "admin/img/icon-unknown.svg" %}" class="help help-tooltip" width="10" height="10" alt="({{ field.help_text|striptags }})" title="{{ field.help_text|striptags }}" />{% endif %}
</th> </th>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
@ -34,7 +36,7 @@
{{ inline_admin_form.original }} {{ inline_admin_form.original }}
{% if inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %}<a href="{% url inline_admin_form.model_admin.opts|admin_urlname:'change' inline_admin_form.original.pk|admin_urlquote %}" class="inlinechangelink">{% trans "Change" %}</a>{% endif %} {% if inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %}<a href="{% url inline_admin_form.model_admin.opts|admin_urlname:'change' inline_admin_form.original.pk|admin_urlquote %}" class="inlinechangelink">{% trans "Change" %}</a>{% endif %}
{% endif %} {% endif %}
{% if inline_admin_form.show_url %}<a href="{% url 'admin:view_on_site' inline_admin_form.original_content_type_id inline_admin_form.original.pk %}">{% trans "View on site" %}</a>{% endif %} {% if inline_admin_form.show_url %}<a href="{{ inline_admin_form.absolute_url }}">{% trans "View on site" %}</a>{% endif %}
</p>{% endif %} </p>{% endif %}
{% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %} {% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
{{ inline_admin_form.fk_field.field }} {{ inline_admin_form.fk_field.field }}
@ -42,7 +44,7 @@
{% for fieldset in inline_admin_form %} {% for fieldset in inline_admin_form %}
{% for line in fieldset %} {% for line in fieldset %}
{% for field in line %} {% for field in line %}
{% if field.is_hidden %} {{ field.field }} {% endif %} {% if field.field.is_hidden %} {{ field.field }} {% endif %}
{% endfor %} {% endfor %}
{% endfor %} {% endfor %}
{% endfor %} {% endfor %}
@ -54,14 +56,16 @@
{% for fieldset in inline_admin_form %} {% for fieldset in inline_admin_form %}
{% for line in fieldset %} {% for line in fieldset %}
{% for field in line %} {% for field in line %}
{% if not field.field.is_hidden %}
<td{% if field.field.name %} class="field-{{ field.field.name }}"{% endif %}> <td{% if field.field.name %} class="field-{{ field.field.name }}"{% endif %}>
{% if field.is_readonly %} {% if field.is_readonly %}
<p>{{ field.contents|linebreaksbr }}</p> <p>{{ field.contents }}</p>
{% else %} {% else %}
{{ field.field.errors.as_ul }} {{ field.field.errors.as_ul }}
{{ field.field }} {{ field.field }}
{% endif %} {% endif %}
</td> </td>
{% endif %}
{% endfor %} {% endfor %}
{% endfor %} {% endfor %}
{% endfor %} {% endfor %}
@ -75,15 +79,3 @@
</fieldset> </fieldset>
</div> </div>
</div> </div>
<script type="text/javascript">
(function($) {
$("#{{ inline_admin_formset.formset.prefix }}-group .tabular.inline-related tbody tr").tabularFormset({
prefix: "{{ inline_admin_formset.formset.prefix }}",
adminStaticPrefix: '{% static "admin/" %}',
addText: "{% blocktrans with inline_admin_formset.opts.verbose_name|title as verbose_name %}Add another {{ verbose_name }}{% endblocktrans %}",
deleteText: "{% trans 'Remove' %}"
});
})(django.jQuery);
</script>

View File

@ -188,3 +188,5 @@ AUTH_PASSWORD_VALIDATORS = [
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
}, },
] ]
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'

View File

@ -12,7 +12,6 @@ setup(
'Intended Audience :: Developers', 'Intended Audience :: Developers',
'License :: OSI Approved :: Apache Software License', 'License :: OSI Approved :: Apache Software License',
'Operating System :: OS Independent', 'Operating System :: OS Independent',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3',
'Topic :: Utilities'], 'Topic :: Utilities'],
description='Drag and drop sorting for models and inline models in Django admin.', description='Drag and drop sorting for models and inline models in Django admin.',

View File

@ -1,11 +1,12 @@
[tox] [tox]
envlist = django{2.2,3.0}-{py36,py37,py38},coverage envlist = django{2.2,3.1,3.2}-{py36,py37,py38,py39},coverage
[testenv] [testenv]
deps = deps =
coverage coverage
django2.2: Django>=2.2 django2.2: Django>=2.2
django3.0: Django>=3.0 django3.1: Django>=3.1
django3.2: Django>=3.2
whitelist_externals = cd whitelist_externals = cd
setenv = setenv =
PYTHONPATH = {toxinidir}/sample_project PYTHONPATH = {toxinidir}/sample_project