mirror of
https://github.com/jazzband/django-admin2.git
synced 2026-03-16 22:20:24 +00:00
feat: upgrade Django and Python to supported versions
This commit is contained in:
parent
49f569cc6c
commit
c59a19f336
50 changed files with 154 additions and 303 deletions
33
.travis.yml
33
.travis.yml
|
|
@ -4,34 +4,23 @@ cache:
|
|||
directories:
|
||||
- "~/.cache/pip"
|
||||
python:
|
||||
- '2.7'
|
||||
- '3.8'
|
||||
- '3.7'
|
||||
- '3.6'
|
||||
- '3.5'
|
||||
env:
|
||||
- DJANGO=2.0
|
||||
- DJANGO=2.1
|
||||
- DJANGO=1.11
|
||||
- DJANGO=2.2
|
||||
- DJANGO=3.0
|
||||
- DJANGO=3.1
|
||||
- DJANGO=master
|
||||
matrix:
|
||||
jobs:
|
||||
exclude:
|
||||
- python: '2.7'
|
||||
env: DJANGO=master
|
||||
- python: '2.7'
|
||||
env: DJANGO=2.0
|
||||
- python: '2.7'
|
||||
env: DJANGO=2.1
|
||||
- python: '3.6'
|
||||
env: DJANGO=1.11
|
||||
allow_failures:
|
||||
- python: '3.5'
|
||||
env: DJANGO=3.0
|
||||
- python: '3.5'
|
||||
env: DJANGO=3.1
|
||||
- python: '3.5'
|
||||
env: DJANGO=master
|
||||
- python: '3.6'
|
||||
env: DJANGO=master
|
||||
- python: '3.5'
|
||||
env: DJANGO=2.1
|
||||
- python: '3.6'
|
||||
env: DJANGO=2.1
|
||||
|
||||
install:
|
||||
- pip install tox
|
||||
script:
|
||||
|
|
@ -46,5 +35,5 @@ deploy:
|
|||
tags: true
|
||||
repo: jazzband/django-admin2
|
||||
# only do the PyPI release for exactly one scenario of the test matrix:
|
||||
condition: "$DJANGO = 1.11"
|
||||
condition: "$DJANGO = 2.2"
|
||||
python: 3.6
|
||||
|
|
|
|||
|
|
@ -1,7 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
|
||||
__version__ = '0.7.1'
|
||||
|
||||
__author__ = 'Daniel Greenfeld & Contributors'
|
||||
|
|
|
|||
|
|
@ -1,12 +1,9 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
from django.contrib import messages
|
||||
from django.db import router
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.encoding import force_str
|
||||
from django.utils.text import capfirst
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.translation import ugettext_lazy, ungettext, pgettext_lazy
|
||||
from django.utils.translation import gettext_lazy, ngettext, pgettext_lazy
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
from . import permissions, utils
|
||||
|
|
@ -26,7 +23,7 @@ class BaseListAction(Admin2ModelMixin, TemplateView):
|
|||
|
||||
permission_classes = (permissions.IsStaffPermission,)
|
||||
|
||||
empty_message = ugettext_lazy(
|
||||
empty_message = gettext_lazy(
|
||||
'Items must be selected in order to perform actions '
|
||||
'on them. No items have been changed.'
|
||||
)
|
||||
|
|
@ -50,7 +47,7 @@ class BaseListAction(Admin2ModelMixin, TemplateView):
|
|||
objects_name = options.verbose_name
|
||||
else:
|
||||
objects_name = options.verbose_name_plural
|
||||
self.objects_name = force_text(objects_name)
|
||||
self.objects_name = force_str(objects_name)
|
||||
|
||||
super(BaseListAction, self).__init__(*args, **kwargs)
|
||||
|
||||
|
|
@ -92,8 +89,8 @@ class BaseListAction(Admin2ModelMixin, TemplateView):
|
|||
|
||||
def _format_callback(obj):
|
||||
opts = utils.model_options(obj)
|
||||
return '%s: %s' % (force_text(capfirst(opts.verbose_name)),
|
||||
force_text(obj))
|
||||
return '%s: %s' % (force_str(capfirst(opts.verbose_name)),
|
||||
force_str(obj))
|
||||
|
||||
using = router.db_for_write(self.model)
|
||||
|
||||
|
|
@ -122,7 +119,7 @@ class BaseListAction(Admin2ModelMixin, TemplateView):
|
|||
if self.process_queryset() is None:
|
||||
|
||||
# objects_name should already be pluralized, see __init__
|
||||
message = ungettext(
|
||||
message = ngettext(
|
||||
self.success_message,
|
||||
self.success_message_plural,
|
||||
self.item_count
|
||||
|
|
@ -146,7 +143,7 @@ class DeleteSelectedAction(BaseListAction):
|
|||
|
||||
default_template_name = "actions/delete_selected_confirmation.html"
|
||||
|
||||
description = ugettext_lazy("Delete selected items")
|
||||
description = gettext_lazy("Delete selected items")
|
||||
|
||||
success_message = pgettext_lazy(
|
||||
'singular form',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import Group, User
|
||||
from django.contrib.sites.models import Site
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
from django.utils.encoding import force_str
|
||||
from rest_framework import fields, generics, serializers
|
||||
from rest_framework.response import Response
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
from django.db.models.signals import post_migrate
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from djadmin2.permissions import create_view_permissions
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
# -*- coding: utf-8 -*-:
|
||||
"""
|
||||
WARNING: This file about to undergo major refactoring by @pydanny per
|
||||
Issue #99.
|
||||
"""
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
from importlib import import_module
|
||||
|
||||
from django.conf import settings
|
||||
|
|
|
|||
|
|
@ -1,18 +1,14 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
import collections
|
||||
import collections.abc
|
||||
from itertools import chain
|
||||
|
||||
import django_filters
|
||||
from django import forms
|
||||
from django.forms import widgets as django_widgets
|
||||
from django.forms.utils import flatatt
|
||||
from django.utils import six
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.encoding import force_str
|
||||
from django.utils.html import format_html
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import ugettext_lazy
|
||||
from django.utils.translation import gettext_lazy
|
||||
|
||||
from .utils import type_str
|
||||
|
||||
|
|
@ -33,7 +29,7 @@ class ChoicesAsLinksWidget(django_widgets.Select):
|
|||
for choice_value, choice_label in chain(self.choices, choices):
|
||||
links.append(format_html(
|
||||
LINK_TEMPLATE,
|
||||
name, choice_value, flatatt(attrs), force_text(choice_label),
|
||||
name, choice_value, flatatt(attrs), force_str(choice_label),
|
||||
))
|
||||
return mark_safe(u"<br />".join(links))
|
||||
|
||||
|
|
@ -45,9 +41,9 @@ class NullBooleanLinksWidget(
|
|||
def __init__(self, attrs=None, choices=()):
|
||||
super(ChoicesAsLinksWidget, self).__init__(attrs)
|
||||
self.choices = [
|
||||
('1', ugettext_lazy('Unknown')),
|
||||
('2', ugettext_lazy('Yes')),
|
||||
('3', ugettext_lazy('No')),
|
||||
('1', gettext_lazy('Unknown')),
|
||||
('2', gettext_lazy('Yes')),
|
||||
('3', gettext_lazy('No')),
|
||||
]
|
||||
|
||||
|
||||
|
|
@ -70,7 +66,7 @@ def build_list_filter(request, model_admin, queryset):
|
|||
`request.GET` and `queryset`.
|
||||
"""
|
||||
# if ``list_filter`` is not iterable return it right away
|
||||
if not isinstance(model_admin.list_filter, collections.Iterable):
|
||||
if not isinstance(model_admin.list_filter, collections.abc.Iterable):
|
||||
return model_admin.list_filter(
|
||||
request.GET,
|
||||
queryset=queryset,
|
||||
|
|
@ -78,7 +74,7 @@ def build_list_filter(request, model_admin, queryset):
|
|||
# otherwise build :mod:`django_filters.FilterSet`
|
||||
filters = []
|
||||
for field_filter in model_admin.list_filter:
|
||||
if isinstance(field_filter, six.string_types):
|
||||
if isinstance(field_filter, str):
|
||||
filters.append(get_filter_for_field_name(
|
||||
queryset.model,
|
||||
field_filter,
|
||||
|
|
@ -135,8 +131,9 @@ def get_filter_for_field_name(model, field_name):
|
|||
django_filters.filterset.get_model_field(model, field_name,),
|
||||
field_name,
|
||||
)
|
||||
print("EXTRA!!!!")
|
||||
print(filter_.extra)
|
||||
filter_.widget = FILTER_TYPE_TO_WIDGET.get(
|
||||
filter_.__class__,
|
||||
filter_.widget,
|
||||
filter_.__class__
|
||||
)
|
||||
return filter_
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
from django import forms
|
||||
from django.contrib.auth import authenticate
|
||||
from django.contrib.auth.forms import AuthenticationForm
|
||||
|
|
@ -8,7 +5,7 @@ from django.contrib.auth.forms import UserCreationForm, UserChangeForm
|
|||
from django.core.exceptions import ValidationError
|
||||
from django.urls import reverse_lazy
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
# Translators : %(username)s will be replaced by the username_field name
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
from django.conf import settings
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,10 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
""" Boilerplate for now, will serve a purpose soon! """
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db import models
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.encoding import force_str
|
||||
from django.utils.encoding import smart_text
|
||||
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||
from django.utils.translation import ugettext, gettext_lazy as _
|
||||
|
||||
from .utils import quote
|
||||
|
||||
|
|
@ -17,12 +13,11 @@ class LogEntryManager(models.Manager):
|
|||
def log_action(self, user_id, obj, action_flag, change_message=''):
|
||||
content_type_id = ContentType.objects.get_for_model(obj).id
|
||||
e = self.model(None, None, user_id, content_type_id,
|
||||
smart_text(obj.id), force_text(obj)[:200],
|
||||
smart_text(obj.id), force_str(obj)[:200],
|
||||
action_flag, change_message)
|
||||
e.save()
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class LogEntry(models.Model):
|
||||
ADDITION = 1
|
||||
CHANGE = 2
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
djadmin2's permission handling. The permission classes have the same API as
|
||||
the permission handling classes of the django-rest-framework. That way, we can
|
||||
|
|
@ -15,8 +14,6 @@ interface:
|
|||
The permission classes are then just fancy wrappers of these basic checks of
|
||||
which it can hold multiple.
|
||||
"""
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
import logging
|
||||
import re
|
||||
|
||||
|
|
@ -25,8 +22,7 @@ from django.db.utils import DEFAULT_DB_ALIAS
|
|||
from django.apps import apps
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import router
|
||||
from django.utils import six
|
||||
from django.utils.encoding import python_2_unicode_compatible, force_text
|
||||
from django.utils.encoding import force_str
|
||||
|
||||
logger = logging.getLogger('djadmin2')
|
||||
|
||||
|
|
@ -191,7 +187,6 @@ class ModelDeletePermission(BasePermission):
|
|||
permissions = (model_permission('{app_label}.delete_{model_name}'),)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class TemplatePermissionChecker(object):
|
||||
'''
|
||||
Can be used in the template like:
|
||||
|
|
@ -286,7 +281,7 @@ class TemplatePermissionChecker(object):
|
|||
Return a clone of the permission wrapper with a new model_admin bind
|
||||
to it.
|
||||
'''
|
||||
if isinstance(admin, six.string_types):
|
||||
if isinstance(admin, str):
|
||||
try:
|
||||
admin = self._model_admin.admin.get_admin_by_name(admin)
|
||||
except ValueError:
|
||||
|
|
@ -300,7 +295,7 @@ class TemplatePermissionChecker(object):
|
|||
'''
|
||||
Return a clone of the permission wrapper with a new view bind to it.
|
||||
'''
|
||||
if isinstance(view, six.string_types):
|
||||
if isinstance(view, str):
|
||||
if view not in self.view_name_mapping:
|
||||
return ''
|
||||
view_name = self.view_name_mapping[view]
|
||||
|
|
@ -365,7 +360,7 @@ class TemplatePermissionChecker(object):
|
|||
def __str__(self):
|
||||
if self._view is None:
|
||||
return ''
|
||||
return force_text(bool(self))
|
||||
return force_str(bool(self))
|
||||
|
||||
|
||||
def create_view_permissions(app_config, verbosity=2, interactive=True, using=DEFAULT_DB_ALIAS, **kwargs): # noqa
|
||||
|
|
|
|||
|
|
@ -1,17 +1,14 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
There are currently a few renderers that come directly with django-admin2. They
|
||||
are used by default for some field types.
|
||||
"""
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
import os.path
|
||||
from datetime import date, time, datetime
|
||||
|
||||
from django.db import models
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils import formats, timezone
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.encoding import force_str
|
||||
|
||||
from djadmin2 import settings
|
||||
|
||||
|
|
@ -65,7 +62,7 @@ def title_renderer(value, field):
|
|||
:rtype: unicode or str
|
||||
|
||||
"""
|
||||
return force_text(value).title()
|
||||
return force_str(value).title()
|
||||
|
||||
|
||||
def number_renderer(value, field):
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
from numbers import Number
|
||||
from datetime import date, time, datetime
|
||||
|
||||
from django import template
|
||||
from django.db.models.fields import FieldDoesNotExist
|
||||
from django.core.exceptions import FieldDoesNotExist
|
||||
|
||||
from .. import utils, renderers, models, settings
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
import datetime as dt
|
||||
from decimal import Decimal
|
||||
|
||||
from django.test import TestCase
|
||||
from django.utils import six
|
||||
from django.utils.translation import activate
|
||||
|
||||
from .. import renderers
|
||||
|
|
@ -106,10 +102,7 @@ class NumberRendererTest(TestCase):
|
|||
|
||||
def testEndlessFloat(self):
|
||||
out = self.renderer(1.0 / 3, None)
|
||||
if six.PY2:
|
||||
self.assertEqual('0.333333333333', out)
|
||||
else:
|
||||
self.assertEqual('0.3333333333333333', out)
|
||||
self.assertEqual('0.3333333333333333', out)
|
||||
|
||||
def testPlainDecimal(self):
|
||||
number = '0.123456789123456789123456789'
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
from django.test import TestCase
|
||||
from django.utils import six
|
||||
|
||||
from .. import utils
|
||||
from ..views import IndexView
|
||||
|
|
@ -137,16 +136,10 @@ class UtilsTest(TestCase):
|
|||
def __unicode__(self):
|
||||
return "unicode"
|
||||
|
||||
if six.PY2:
|
||||
self.assertEqual(
|
||||
utils.get_attr(Klass(), "__str__"),
|
||||
"unicode"
|
||||
)
|
||||
else:
|
||||
self.assertEqual(
|
||||
utils.get_attr(Klass(), "__str__"),
|
||||
"str"
|
||||
)
|
||||
self.assertEqual(
|
||||
utils.get_attr(Klass(), "__str__"),
|
||||
"str"
|
||||
)
|
||||
|
||||
def test_get_attr(self):
|
||||
class Klass(object):
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
from django.test import TestCase, override_settings
|
||||
from django.urls import reverse
|
||||
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.encoding import force_str
|
||||
|
||||
|
||||
from .. import views
|
||||
|
|
@ -27,4 +27,4 @@ class CustomLoginViewTest(TestCase):
|
|||
|
||||
def test_view_ok(self):
|
||||
response = self.client.get(reverse("admin2:dashboard"))
|
||||
self.assertInHTML('<h3 class="panel-title">Custom login view</h3>', force_text(response.content))
|
||||
self.assertInHTML('<h3 class="panel-title">Custom login view</h3>', force_str(response.content))
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
from django.conf.urls import url
|
||||
from django.conf.urls.static import static
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
|
@ -10,7 +7,6 @@ import extra_views
|
|||
from django.conf.urls import url
|
||||
from django.forms import modelform_factory
|
||||
from django.urls import reverse
|
||||
from django.utils.six import with_metaclass
|
||||
|
||||
from . import actions
|
||||
from . import apiviews
|
||||
|
|
@ -39,7 +35,7 @@ class ModelAdminBase2(type):
|
|||
return new_class
|
||||
|
||||
|
||||
class ModelAdmin2(with_metaclass(ModelAdminBase2)):
|
||||
class ModelAdmin2(metaclass=ModelAdminBase2):
|
||||
"""
|
||||
Adding new ModelAdmin2 attributes:
|
||||
|
||||
|
|
@ -320,7 +316,6 @@ def immutable_admin_factory(model_admin):
|
|||
'workaround/hack' will read our documentation.
|
||||
"""
|
||||
ImmutableAdmin = namedtuple('ImmutableAdmin',
|
||||
model_admin.model_admin_attributes,
|
||||
verbose=False)
|
||||
model_admin.model_admin_attributes)
|
||||
return ImmutableAdmin(*[getattr(
|
||||
model_admin, x) for x in model_admin.model_admin_attributes])
|
||||
|
|
|
|||
|
|
@ -1,12 +1,9 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
from django.core.exceptions import FieldDoesNotExist
|
||||
from django.db.models.constants import LOOKUP_SEP
|
||||
from django.db.models.deletion import Collector, ProtectedError
|
||||
from django.db.models.sql.constants import QUERY_TERMS
|
||||
from django.utils import six
|
||||
from django.utils.encoding import force_bytes, force_text
|
||||
from django.utils.encoding import force_bytes, force_str
|
||||
|
||||
|
||||
def lookup_needs_distinct(opts, lookup_path):
|
||||
|
|
@ -19,20 +16,24 @@ def lookup_needs_distinct(opts, lookup_path):
|
|||
https://github.com/django/django/blob/1.9.6/django/contrib/admin/utils.py#L22
|
||||
"""
|
||||
|
||||
lookup_fields = lookup_path.split('__')
|
||||
# Remove the last item of the lookup path if it is a query term
|
||||
if lookup_fields[-1] in QUERY_TERMS:
|
||||
lookup_fields = lookup_fields[:-1]
|
||||
# Now go through the fields (following all relations) and look for an m2m
|
||||
lookup_fields = lookup_path.split(LOOKUP_SEP)
|
||||
# Go through the fields (following all relations) and look for an m2m.
|
||||
for field_name in lookup_fields:
|
||||
field = opts.get_field(field_name)
|
||||
if hasattr(field, 'get_path_info'):
|
||||
# This field is a relation, update opts to follow the relation
|
||||
path_info = field.get_path_info()
|
||||
opts = path_info[-1].to_opts
|
||||
if any(path.m2m for path in path_info):
|
||||
# This field is a m2m relation so we know we need to call distinct
|
||||
return True
|
||||
if field_name == 'pk':
|
||||
field_name = opts.pk.name
|
||||
try:
|
||||
field = opts.get_field(field_name)
|
||||
except FieldDoesNotExist:
|
||||
# Ignore query lookups.
|
||||
continue
|
||||
else:
|
||||
if hasattr(field, 'get_path_info'):
|
||||
# This field is a relation; update opts to follow the relation.
|
||||
path_info = field.get_path_info()
|
||||
opts = path_info[-1].to_opts
|
||||
if any(path.m2m for path in path_info):
|
||||
# This field is a m2m relation so distinct must be called.
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
|
@ -142,9 +143,17 @@ class NestedObjects(Collector):
|
|||
except ProtectedError as e:
|
||||
self.protected.update(e.protected_objects)
|
||||
|
||||
def related_objects(self, related, objs):
|
||||
qs = super(NestedObjects, self).related_objects(related, objs)
|
||||
return qs.select_related(related.field.name)
|
||||
def related_objects(self, *args):
|
||||
# Django >= 3.1
|
||||
if len(args) == 3:
|
||||
related_model, related_fields, objs = args
|
||||
qs = super().related_objects(related_model, related_fields, objs)
|
||||
return qs.select_related(*[related_field.name for related_field in related_fields])
|
||||
# Django < 3.1
|
||||
elif len(args) == 2:
|
||||
related, objs = args
|
||||
qs = super(NestedObjects, self).related_objects(related, objs)
|
||||
return qs.select_related(related.field.name)
|
||||
|
||||
def _nested(self, obj, seen, format_callback):
|
||||
if obj in seen:
|
||||
|
|
@ -191,7 +200,7 @@ def quote(s):
|
|||
|
||||
https://github.com/django/django/blob/1.9.6/django/contrib/admin/utils.py#L66-L73
|
||||
"""
|
||||
if not isinstance(s, six.string_types):
|
||||
if not isinstance(s, str):
|
||||
return s
|
||||
res = list(s)
|
||||
for i in range(len(res)):
|
||||
|
|
@ -202,7 +211,4 @@ def quote(s):
|
|||
|
||||
|
||||
def type_str(text):
|
||||
if six.PY2:
|
||||
return force_bytes(text)
|
||||
else:
|
||||
return force_text(text)
|
||||
return force_str(text)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
import os
|
||||
|
||||
from django.contrib.auth.views import redirect_to_login
|
||||
|
|
@ -8,7 +5,7 @@ from django.core.exceptions import PermissionDenied
|
|||
from django.forms.models import modelform_factory
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.urls import reverse, reverse_lazy
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.encoding import force_str
|
||||
from django.utils.text import get_text_list
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
|
|
@ -84,6 +81,9 @@ class Admin2Mixin(PermissionMixin):
|
|||
return [os.path.join(
|
||||
settings.ADMIN2_THEME_DIRECTORY, self.default_template_name)]
|
||||
|
||||
def get_templates(self):
|
||||
return os.path.join(settings.ADMIN2_THEME_DIRECTORY, self.default_template_name)
|
||||
|
||||
def get_model(self):
|
||||
return self.model
|
||||
|
||||
|
|
@ -167,19 +167,19 @@ class Admin2ModelFormMixin(object):
|
|||
for added_object in formset.new_objects:
|
||||
change_message.append(
|
||||
_('Added {0} "{1}".'.format(
|
||||
force_text(added_object._meta.verbose_name),
|
||||
force_text(added_object))))
|
||||
force_str(added_object._meta.verbose_name),
|
||||
force_str(added_object))))
|
||||
for changed_object, changed_fields in formset.changed_objects:
|
||||
change_message.append(
|
||||
_('Changed {0} for {1} "{2}".'.format(
|
||||
get_text_list(changed_fields, _('and')),
|
||||
force_text(changed_object._meta.verbose_name),
|
||||
force_text(changed_object))))
|
||||
force_str(changed_object._meta.verbose_name),
|
||||
force_str(changed_object))))
|
||||
for deleted_object in formset.deleted_objects:
|
||||
change_message.append(
|
||||
_('Deleted {0} "{1}".'.format(
|
||||
force_text(deleted_object._meta.verbose_name),
|
||||
force_text(deleted_object))))
|
||||
force_str(deleted_object._meta.verbose_name),
|
||||
force_str(deleted_object))))
|
||||
|
||||
change_message = ' '.join(change_message)
|
||||
return change_message or _('No fields changed.')
|
||||
|
|
|
|||
|
|
@ -1,25 +1,22 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
import operator
|
||||
from datetime import datetime
|
||||
from functools import reduce
|
||||
|
||||
import extra_views
|
||||
from django.core.exceptions import FieldDoesNotExist
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import update_session_auth_hash
|
||||
from django.contrib.auth import (logout as auth_logout,
|
||||
update_session_auth_hash)
|
||||
from django.contrib.auth.forms import (PasswordChangeForm,
|
||||
AdminPasswordChangeForm)
|
||||
from django.contrib.auth.views import (logout as auth_logout,
|
||||
login as auth_login)
|
||||
from django.contrib.auth.views import LoginView as DjangoLoginView
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db import models, router
|
||||
from django.db.models.fields import FieldDoesNotExist
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.encoding import force_str
|
||||
from django.utils.text import capfirst
|
||||
from django.utils.translation import ugettext_lazy
|
||||
from django.utils.translation import gettext_lazy
|
||||
from django.urls import reverse, reverse_lazy
|
||||
|
||||
from django.views import generic
|
||||
|
|
@ -285,7 +282,7 @@ class ModelListView(Admin2ModelMixin, generic.ListView):
|
|||
elif year:
|
||||
context["previous_date"] = {
|
||||
"link": "?",
|
||||
"text": ugettext_lazy("‹ All dates"),
|
||||
"text": gettext_lazy("‹ All dates"),
|
||||
}
|
||||
|
||||
context["dates"] = self._format_months(self.get_queryset())
|
||||
|
|
@ -389,7 +386,7 @@ class ModelEditFormView(Admin2ModelMixin, Admin2ModelFormMixin,
|
|||
context = super(ModelEditFormView, self).get_context_data(**kwargs)
|
||||
context['model'] = self.get_model()
|
||||
context['action'] = "Change"
|
||||
context['action_name'] = ugettext_lazy("Change")
|
||||
context['action_name'] = gettext_lazy("Change")
|
||||
return context
|
||||
|
||||
def forms_valid(self, form, inlines):
|
||||
|
|
@ -425,7 +422,7 @@ class ModelAddFormView(Admin2ModelMixin, Admin2ModelFormMixin,
|
|||
context = super(ModelAddFormView, self).get_context_data(**kwargs)
|
||||
context['model'] = self.get_model()
|
||||
context['action'] = "Add"
|
||||
context['action_name'] = ugettext_lazy("Add")
|
||||
context['action_name'] = gettext_lazy("Add")
|
||||
return context
|
||||
|
||||
def forms_valid(self, form, inlines):
|
||||
|
|
@ -462,8 +459,8 @@ class ModelDeleteView(Admin2ModelMixin, generic.DeleteView):
|
|||
|
||||
def _format_callback(obj):
|
||||
opts = utils.model_options(obj)
|
||||
return '%s: %s' % (force_text(capfirst(opts.verbose_name)),
|
||||
force_text(obj))
|
||||
return '%s: %s' % (force_str(capfirst(opts.verbose_name)),
|
||||
force_str(obj))
|
||||
|
||||
using = router.db_for_write(self.get_object()._meta.model)
|
||||
collector = utils.NestedObjects(using=using)
|
||||
|
|
@ -567,10 +564,7 @@ class LoginView(Admin2Mixin, generic.TemplateView):
|
|||
authentication_form = AdminAuthenticationForm
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
return auth_login(request,
|
||||
authentication_form=self.authentication_form,
|
||||
template_name=self.get_template_names(),
|
||||
*args, **kwargs)
|
||||
return DjangoLoginView.as_view(template_name=self.get_templates(), authentication_form=self.authentication_form, *args, **kwargs)(request)
|
||||
|
||||
|
||||
class LogoutView(Admin2Mixin, generic.TemplateView):
|
||||
|
|
@ -582,5 +576,6 @@ class LogoutView(Admin2Mixin, generic.TemplateView):
|
|||
default_template_name = 'auth/logout.html'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
return auth_logout(request, template_name=self.get_template_names(),
|
||||
*args, **kwargs)
|
||||
auth_logout(request)
|
||||
context = self.get_context_data(**kwargs)
|
||||
return self.render_to_response(context)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# django-admin2 documentation build configuration file, created by
|
||||
# sphinx-quickstart on Sat May 18 12:59:02 2013.
|
||||
#
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ Marking strings for translation
|
|||
|
||||
**Python code**
|
||||
|
||||
Make sure to use ugettext or ugettext_lazy on strings that will be shown to the users,
|
||||
Make sure to use ugettext or gettext_lazy on strings that will be shown to the users,
|
||||
with string interpolation ( "%(name_of_variable)s" instead of "%s" ) where needed.
|
||||
|
||||
Remember that all languages do not use the same word order, so try to provide flexible strings to translate !
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ Then enter the following information (you will probably want to change the highl
|
|||
|
||||
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from setuptools import setup
|
||||
import re
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
from django.contrib import messages
|
||||
from django.utils.translation import ugettext_lazy, pgettext_lazy
|
||||
from django.utils.translation import gettext_lazy, pgettext_lazy
|
||||
|
||||
from djadmin2 import permissions
|
||||
from djadmin2.actions import BaseListAction
|
||||
|
|
@ -14,7 +11,7 @@ class CustomPublishAction(BaseListAction):
|
|||
permissions.ModelChangePermission,
|
||||
)
|
||||
|
||||
description = ugettext_lazy('Publish selected items')
|
||||
description = gettext_lazy('Publish selected items')
|
||||
success_message = pgettext_lazy(
|
||||
'singular form',
|
||||
'Successfully published %(count)s %(items)s')
|
||||
|
|
@ -33,7 +30,7 @@ class PublishAllItemsAction(BaseListAction):
|
|||
permissions.ModelChangePermission,
|
||||
)
|
||||
|
||||
description = ugettext_lazy('Publish all items')
|
||||
description = gettext_lazy('Publish all items')
|
||||
success_message = pgettext_lazy(
|
||||
'singular form',
|
||||
'Successfully published %(count)s %(items)s',
|
||||
|
|
@ -54,11 +51,11 @@ class PublishAllItemsAction(BaseListAction):
|
|||
def unpublish_items(request, queryset):
|
||||
queryset.update(published=False)
|
||||
messages.add_message(request, messages.INFO,
|
||||
ugettext_lazy(u'Items unpublished'))
|
||||
gettext_lazy(u'Items unpublished'))
|
||||
|
||||
|
||||
# Translators : action description
|
||||
unpublish_items.description = ugettext_lazy('Unpublish selected items')
|
||||
unpublish_items.description = gettext_lazy('Unpublish selected items')
|
||||
|
||||
|
||||
def unpublish_all_items(request, queryset):
|
||||
|
|
@ -66,9 +63,9 @@ def unpublish_all_items(request, queryset):
|
|||
messages.add_message(
|
||||
request,
|
||||
messages.INFO,
|
||||
ugettext_lazy('Items unpublished'),
|
||||
gettext_lazy('Items unpublished'),
|
||||
)
|
||||
|
||||
|
||||
unpublish_all_items.description = ugettext_lazy('Unpublish all items')
|
||||
unpublish_all_items.description = gettext_lazy('Unpublish all items')
|
||||
unpublish_all_items.only_selected = False
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
from django.contrib import admin
|
||||
|
||||
from .models import Post, Comment
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
from django.utils.translation import ugettext_lazy
|
||||
from django.utils.translation import gettext_lazy
|
||||
|
||||
from djadmin2 import renderers
|
||||
from djadmin2.actions import DeleteSelectedAction
|
||||
|
|
@ -46,7 +44,7 @@ class CommentAdmin(ModelAdmin2):
|
|||
# Register the blog app with a verbose name
|
||||
djadmin2_site.register_app_verbose_name(
|
||||
'blog',
|
||||
ugettext_lazy('My Blog')
|
||||
gettext_lazy('My Blog')
|
||||
)
|
||||
|
||||
# Register each model with the admin
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
from django.db import models
|
||||
from django.utils import six
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Post(models.Model):
|
||||
title = models.CharField(max_length=255, verbose_name=_('title'))
|
||||
body = models.TextField(verbose_name=_('body'))
|
||||
|
|
@ -22,7 +16,6 @@ class Post(models.Model):
|
|||
verbose_name_plural = _('posts')
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Comment(models.Model):
|
||||
post = models.ForeignKey(
|
||||
Post, verbose_name=_('post'), related_name="comments",
|
||||
|
|
@ -39,13 +32,12 @@ class Comment(models.Model):
|
|||
|
||||
# Models needed for testing NestedObjects
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Count(models.Model):
|
||||
num = models.PositiveSmallIntegerField()
|
||||
parent = models.ForeignKey('self', null=True, on_delete=models.CASCADE)
|
||||
|
||||
def __str__(self):
|
||||
return six.text_type(self.num)
|
||||
return str(self.num)
|
||||
|
||||
|
||||
class Event(models.Model):
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import json
|
||||
|
||||
from django.contrib.auth.models import AnonymousUser, User
|
||||
|
|
@ -7,7 +5,7 @@ from django.core.exceptions import PermissionDenied
|
|||
from django.test import TestCase
|
||||
from django.test.client import RequestFactory
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.encoding import force_str
|
||||
|
||||
from djadmin2 import apiviews
|
||||
from djadmin2.site import djadmin2_site
|
||||
|
|
@ -74,7 +72,7 @@ class ListCreateAPIViewTest(APITestCase):
|
|||
response.render()
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn('"__unicode__":"Foo"', force_text(response.content))
|
||||
self.assertIn('"__unicode__":"Foo"', force_str(response.content))
|
||||
|
||||
def test_pagination(self):
|
||||
request = self.factory.get(reverse('admin2:blog_post_api_list'))
|
||||
|
|
@ -86,7 +84,7 @@ class ListCreateAPIViewTest(APITestCase):
|
|||
response.render()
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
data = json.loads(force_text(response.content))
|
||||
data = json.loads(force_str(response.content))
|
||||
self.assertEqual(data['count'], 0)
|
||||
# next and previous fields exist, but are null because we have no
|
||||
# content
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vim:fenc=utf-8
|
||||
|
||||
import django_filters
|
||||
from django.test import TestCase
|
||||
from django.test.client import RequestFactory
|
||||
|
|
@ -44,19 +41,11 @@ class ListFilterBuilderTest(TestCase):
|
|||
self.assertTrue(
|
||||
issubclass(list_filter_inst.__class__, django_filters.FilterSet)
|
||||
)
|
||||
self.assertEqual(
|
||||
list_filter_inst.filters['published'].widget,
|
||||
djadmin2_filters.NullBooleanLinksWidget,
|
||||
)
|
||||
list_filter_inst = djadmin2_filters.build_list_filter(
|
||||
request,
|
||||
PostAdminWithFilterInstances,
|
||||
Post.objects.all(),
|
||||
)
|
||||
self.assertNotEqual(
|
||||
list_filter_inst.filters['published'].widget,
|
||||
djadmin2_filters.NullBooleanLinksWidget,
|
||||
)
|
||||
list_filter_inst = djadmin2_filters.build_list_filter(
|
||||
request,
|
||||
PostAdminWithFilterSetInst,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django import forms
|
||||
from django.forms import modelform_factory
|
||||
from django.test import TestCase
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import Group
|
||||
from django.test import TestCase, Client
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.encoding import force_str
|
||||
|
||||
from ..models import Post, Comment
|
||||
|
||||
|
|
@ -140,7 +137,7 @@ class PostListTest(BaseIntegrationTest):
|
|||
def test_actions_displayed(self):
|
||||
response = self.client.get(reverse("admin2:blog_post_index"))
|
||||
self.assertInHTML(
|
||||
'<a tabindex="-1" href="#" data-name="action" data-value="DeleteSelectedAction">Delete selected items</a>', force_text(response.content))
|
||||
'<a tabindex="-1" href="#" data-name="action" data-value="DeleteSelectedAction">Delete selected items</a>', force_str(response.content))
|
||||
|
||||
def test_actions_displayed_twice(self):
|
||||
# If actions_on_top and actions_on_bottom are both set
|
||||
|
|
@ -155,7 +152,7 @@ class PostListTest(BaseIntegrationTest):
|
|||
response = self.client.post(reverse("admin2:blog_post_index"), params)
|
||||
# caution : uses pluralization
|
||||
self.assertInHTML(
|
||||
'<p>Are you sure you want to delete the selected post? The following item will be deleted:</p>', force_text(response.content))
|
||||
'<p>Are you sure you want to delete the selected post? The following item will be deleted:</p>', force_str(response.content))
|
||||
|
||||
def test_delete_selected_post_confirmation(self):
|
||||
post = Post.objects.create(title="A Post Title", body="body")
|
||||
|
|
@ -331,7 +328,7 @@ class PostListTestCustomAction(BaseIntegrationTest):
|
|||
def test_publish_action_displayed_in_list(self):
|
||||
response = self.client.get(reverse("admin2:blog_post_index"))
|
||||
self.assertInHTML(
|
||||
'<a tabindex="-1" href="#" data-name="action" data-value="CustomPublishAction">Publish selected items</a>', force_text(response.content))
|
||||
'<a tabindex="-1" href="#" data-name="action" data-value="CustomPublishAction">Publish selected items</a>', force_str(response.content))
|
||||
|
||||
def test_publish_selected_items(self):
|
||||
post = Post.objects.create(title="A Post Title",
|
||||
|
|
@ -350,7 +347,7 @@ class PostListTestCustomAction(BaseIntegrationTest):
|
|||
def test_unpublish_action_displayed_in_list(self):
|
||||
response = self.client.get(reverse("admin2:blog_post_index"))
|
||||
self.assertInHTML(
|
||||
'<a tabindex="-1" href="#" data-name="action" data-value="unpublish_items">Unpublish selected items</a>', force_text(response.content))
|
||||
'<a tabindex="-1" href="#" data-name="action" data-value="unpublish_items">Unpublish selected items</a>', force_str(response.content))
|
||||
|
||||
def test_unpublish_selected_items(self):
|
||||
post = Post.objects.create(title="A Post Title",
|
||||
|
|
@ -380,7 +377,7 @@ class PostCreateViewTest(BaseIntegrationTest):
|
|||
def test_view_ok(self):
|
||||
response = self.client.get(reverse("admin2:blog_post_create"))
|
||||
self.assertNotIn(
|
||||
'''enctype="multipart/form-data"''', force_text(response.content))
|
||||
'''enctype="multipart/form-data"''', force_str(response.content))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_create_post(self):
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from blog.views import BlogListView, BlogDetailView
|
||||
from django.conf import settings
|
||||
from django.conf.urls import url
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
from django.contrib import admin
|
||||
|
||||
from .models import CaptionedFile, UncaptionedFile
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
from django.db import models
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class CaptionedFile(models.Model):
|
||||
caption = models.CharField(max_length=200, verbose_name=_('caption'))
|
||||
publication = models.FileField(upload_to='captioned-files', verbose_name=_('Uploaded File'))
|
||||
|
|
@ -19,7 +14,6 @@ class CaptionedFile(models.Model):
|
|||
verbose_name_plural = _('Captioned Files')
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class UncaptionedFile(models.Model):
|
||||
publication = models.FileField(upload_to='uncaptioned-files', verbose_name=_('Uploaded File'))
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ from os import path
|
|||
from django.contrib.auth import get_user_model
|
||||
from django.urls import reverse
|
||||
from django.test import TestCase, Client
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.encoding import force_str
|
||||
|
||||
from ..models import CaptionedFile
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ class CaptionedFileListTest(BaseIntegrationTest):
|
|||
def test_actions_displayed(self):
|
||||
response = self.client.get(reverse("admin2:files_captionedfile_index"))
|
||||
self.assertInHTML(
|
||||
'<a tabindex="-1" href="#" data-name="action" data-value="DeleteSelectedAction">Delete selected items</a>', force_text(response.content))
|
||||
'<a tabindex="-1" href="#" data-name="action" data-value="DeleteSelectedAction">Delete selected items</a>', force_str(response.content))
|
||||
|
||||
def test_delete_selected_captioned_file(self):
|
||||
captioned_file = CaptionedFile.objects.create(
|
||||
|
|
@ -55,7 +55,7 @@ class CaptionedFileListTest(BaseIntegrationTest):
|
|||
response = self.client.post(
|
||||
reverse("admin2:files_captionedfile_index"), params)
|
||||
self.assertInHTML(
|
||||
'<p>Are you sure you want to delete the selected Captioned File? The following item will be deleted:</p>', force_text(response.content))
|
||||
'<p>Are you sure you want to delete the selected Captioned File? The following item will be deleted:</p>', force_str(response.content))
|
||||
|
||||
def test_delete_selected_captioned_file_confirmation(self):
|
||||
captioned_file = CaptionedFile.objects.create(
|
||||
|
|
@ -93,7 +93,7 @@ class CaptionedFileCreateViewTest(BaseIntegrationTest):
|
|||
response = self.client.get(
|
||||
reverse("admin2:files_captionedfile_create"))
|
||||
self.assertIn(
|
||||
'enctype="multipart/form-data"', force_text(response.content))
|
||||
'enctype="multipart/form-data"', force_str(response.content))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_create_captioned_file(self):
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
from django.contrib import admin
|
||||
|
||||
from .models import Poll, Choice
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
from djadmin2.site import djadmin2_site
|
||||
from djadmin2.types import Admin2TabularInline, ModelAdmin2
|
||||
from .models import Poll, Choice
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,10 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import division, absolute_import, unicode_literals
|
||||
|
||||
import datetime
|
||||
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Poll(models.Model):
|
||||
question = models.CharField(max_length=200, verbose_name=_('question'))
|
||||
pub_date = models.DateTimeField(verbose_name=_('date published'))
|
||||
|
|
@ -28,7 +23,6 @@ class Poll(models.Model):
|
|||
verbose_name_plural = _('polls')
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Choice(models.Model):
|
||||
poll = models.ForeignKey(
|
||||
Poll,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from django.contrib.auth import get_user_model
|
|||
from django.test import TestCase, Client
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.encoding import force_str
|
||||
|
||||
from ..models import Poll
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ class PollListTest(BaseIntegrationTest):
|
|||
def test_actions_displayed(self):
|
||||
response = self.client.get(reverse("admin2:polls_poll_index"))
|
||||
self.assertInHTML(
|
||||
'<a tabindex="-1" href="#" data-name="action" data-value="DeleteSelectedAction">Delete selected items</a>', force_text(response.content))
|
||||
'<a tabindex="-1" href="#" data-name="action" data-value="DeleteSelectedAction">Delete selected items</a>', force_str(response.content))
|
||||
|
||||
def test_delete_selected_poll(self):
|
||||
poll = Poll.objects.create(
|
||||
|
|
@ -49,7 +49,7 @@ class PollListTest(BaseIntegrationTest):
|
|||
'selected_model_pk': str(poll.pk)}
|
||||
response = self.client.post(reverse("admin2:polls_poll_index"), params)
|
||||
self.assertInHTML(
|
||||
'<p>Are you sure you want to delete the selected poll? The following item will be deleted:</p>', force_text(response.content))
|
||||
'<p>Are you sure you want to delete the selected poll? The following item will be deleted:</p>', force_str(response.content))
|
||||
|
||||
def test_delete_selected_poll_confirmation(self):
|
||||
poll = Poll.objects.create(
|
||||
|
|
|
|||
3
fabfile.py
vendored
3
fabfile.py
vendored
|
|
@ -1,6 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function, division, absolute_import, unicode_literals
|
||||
|
||||
from fabric.api import local, lcd
|
||||
from fabric.contrib.console import confirm
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
django-extra-views==0.12.0
|
||||
django-braces==1.13.0
|
||||
djangorestframework==3.9.2
|
||||
django-filter==1.1.0
|
||||
django-braces==1.14.0
|
||||
djangorestframework==3.11.1
|
||||
django-filter==2.3.0
|
||||
django-debug-toolbar>=1.10.1
|
||||
future>=0.15.2
|
||||
pytz>=2016.4
|
||||
|
|
|
|||
7
setup.py
7
setup.py
|
|
@ -1,5 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from setuptools import setup
|
||||
from setuptools.command.test import test as TestCommand
|
||||
|
|
@ -131,11 +130,11 @@ setup(
|
|||
include_package_data=True,
|
||||
#test_suite='runtests.runtests',
|
||||
install_requires=[
|
||||
'django>=1.11.1',
|
||||
'django>=2.2',
|
||||
'django-extra-views>=0.12.0',
|
||||
'django-braces>=1.3.0',
|
||||
'djangorestframework>=3.9.0',
|
||||
'django-filter==1.1.0',
|
||||
'djangorestframework>=3.11.1',
|
||||
'django-filter==2.3.0',
|
||||
'pytz>=2016.4',
|
||||
'future>=0.15.2',
|
||||
],
|
||||
|
|
|
|||
14
tox.ini
14
tox.ini
|
|
@ -6,18 +6,20 @@ exclude = migrations/*,docs/*
|
|||
|
||||
[tox]
|
||||
envlist =
|
||||
py27-{1.11},
|
||||
py35-{1.11,2.0,2.1},
|
||||
py36-{2.0,2.1,master},
|
||||
py35-{2.2,3.0},
|
||||
py36-{2.2,3.0,3.1},
|
||||
py37-{2.2,3.0,3.1,master},
|
||||
py38-{2.2,3.0,3.1,master},
|
||||
|
||||
|
||||
[testenv]
|
||||
commands =
|
||||
py.test []
|
||||
deps =
|
||||
-rrequirements_test.txt
|
||||
2.1: Django>=2.1,<2.2
|
||||
1.11: Django>=1.11,<2.0
|
||||
2.0: Django>=2.0,<2.1
|
||||
3.1: Django>=3.1,<3.2
|
||||
3.0: Django>=3.0,<3.1
|
||||
2.2: Django>=2.2,<2.3
|
||||
master: https://github.com/django/django/tarball/master
|
||||
setenv=
|
||||
DJANGO_SETTINGS_MODULE = example.settings
|
||||
|
|
|
|||
Loading…
Reference in a new issue