commit
8ae64d1ce2
34
.travis.yml
34
.travis.yml
|
|
@ -11,32 +11,38 @@ addons:
|
|||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
# Django 1.11: Python 2.7, 3.5, or 3.6
|
||||
- { env: TOXENV=py27-django111, python: 2.7 }
|
||||
- { env: TOXENV=py35-django111, python: 3.5 }
|
||||
- { env: TOXENV=py36-django111, python: 3.6 }
|
||||
- { env: TOXENV=py36-django111-postgres DB=postgres, python: 3.6 }
|
||||
# Django 2.0: Python 3.5, or 3.6
|
||||
- { env: TOXENV=py35-django20, python: 3.5 }
|
||||
- { env: TOXENV=py36-django20, python: 3.6 }
|
||||
- { env: TOXENV=py36-django20-postgres DB=postgres, python: 3.6 }
|
||||
# Django 2.1: Python 3.6, or 3.7
|
||||
# Django 2.1: Python 3.5, 3.6, or 3.7
|
||||
- { env: TOXENV=py35-django21, python: 3.5 }
|
||||
- { env: TOXENV=py36-django21, python: 3.6 }
|
||||
- { env: TOXENV=py37-django21, python: 3.7 }
|
||||
- { env: TOXENV=py37-django21-postgres DB=postgres, python: 3.7 }
|
||||
# Django 2.2: Python 3.6, or 3.7
|
||||
# Django 2.2: Python 3.5, 3.6, 3.7 or 3.8
|
||||
- { env: TOXENV=py35-django22, python: 3.5 }
|
||||
- { env: TOXENV=py36-django22, python: 3.6 }
|
||||
- { env: TOXENV=py37-django22, python: 3.7 }
|
||||
- { env: TOXENV=py37-django22-postgres DB=postgres, python: 3.7 }
|
||||
- { env: TOXENV=py38-django22, python: 3.8 }
|
||||
- { env: TOXENV=py38-django22-postgres DB=postgres, python: 3.8 }
|
||||
# Django 3.0: Python 3.6, 3.7 or 3.8
|
||||
- { env: TOXENV=py36-django30, python: 3.6 }
|
||||
- { env: TOXENV=py37-django30, python: 3.7 }
|
||||
- { env: TOXENV=py38-django30, python: 3.8 }
|
||||
- { env: TOXENV=py38-django30-postgres DB=postgres, python: 3.8 }
|
||||
# Django 3.1: Python 3.6, 3.7 or 3.8
|
||||
- { env: TOXENV=py36-django31, python: 3.6 }
|
||||
- { env: TOXENV=py37-django31, python: 3.7 }
|
||||
- { env: TOXENV=py38-django31, python: 3.8 }
|
||||
- { env: TOXENV=py38-django31-postgres DB=postgres, python: 3.8 }
|
||||
# Django development master (direct from GitHub source):
|
||||
- { env: TOXENV=py36-djangomaster, python: 3.6 }
|
||||
- { env: TOXENV=py37-djangomaster, python: 3.7 }
|
||||
- { env: TOXENV=py37-djangomaster-postgres DB=postgres, python: 3.7 }
|
||||
- { env: TOXENV=py38-djangomaster, python: 3.8 }
|
||||
- { env: TOXENV=py38-djangomaster-postgres DB=postgres, python: 3.8 }
|
||||
|
||||
allow_failures:
|
||||
- env: TOXENV=py36-djangomaster
|
||||
- env: TOXENV=py37-djangomaster
|
||||
- env: TOXENV=py37-djangomaster-postgres DB=postgres
|
||||
- env: TOXENV=py38-djangomaster
|
||||
- env: TOXENV=py38-djangomaster-postgres DB=postgres
|
||||
|
||||
cache:
|
||||
directories:
|
||||
|
|
|
|||
|
|
@ -62,7 +62,8 @@ Django to perform an ``INNER JOIN`` to fetch the model fields from the database.
|
|||
While taking this in mind, there are valid reasons for using subclassed models.
|
||||
That's what this library is designed for!
|
||||
|
||||
The current release of *django-polymorphic* supports Django 1.11, 2.0, 2.1, 2.2 and Python 2.7 and 3.5+ is supported.
|
||||
The current release of *django-polymorphic* supports Django 2.1, 2.2, 3.0, 3.1
|
||||
and Python 3.5+ is supported.
|
||||
For older Django versions, install *django-polymorphic==1.3*.
|
||||
|
||||
For more information, see the `documentation at Read the Docs <https://django-polymorphic.readthedocs.io/>`_.
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ can be included in a single Django migration. For example:
|
|||
.. code-block:: python
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
from django.db import models
|
||||
from django.utils.dates import MONTHS_3
|
||||
from django.utils.six import python_2_unicode_compatible
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from polymorphic.models import PolymorphicModel
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Order(models.Model):
|
||||
"""
|
||||
An example order that has polymorphic relations
|
||||
|
|
@ -23,7 +21,6 @@ class Order(models.Model):
|
|||
return self.title
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Payment(PolymorphicModel):
|
||||
"""
|
||||
A generic payment model.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
"""
|
||||
The parent admin displays the list view of the base model.
|
||||
"""
|
||||
import sys
|
||||
|
||||
from django.contrib import admin
|
||||
from django.contrib.admin.helpers import AdminErrorList, AdminForm
|
||||
from django.contrib.admin.templatetags.admin_urls import add_preserved_filters
|
||||
|
|
@ -11,6 +9,7 @@ from django.core.exceptions import ImproperlyConfigured, PermissionDenied
|
|||
from django.db import models
|
||||
from django.http import Http404, HttpResponseRedirect
|
||||
from django.template.response import TemplateResponse
|
||||
from django.urls import URLResolver
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.http import urlencode
|
||||
from django.utils.safestring import mark_safe
|
||||
|
|
@ -20,17 +19,6 @@ from polymorphic.utils import get_base_polymorphic_model
|
|||
|
||||
from .forms import PolymorphicModelChoiceForm
|
||||
|
||||
try:
|
||||
# Django 2.0+
|
||||
from django.urls import URLResolver
|
||||
except ImportError:
|
||||
# Django < 2.0
|
||||
from django.urls import RegexURLResolver as URLResolver
|
||||
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
long = int
|
||||
|
||||
|
||||
class RegistrationClosed(RuntimeError):
|
||||
"The admin model can't be registered anymore at this point."
|
||||
|
|
@ -293,9 +281,9 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
|||
try:
|
||||
pos = path.find("/")
|
||||
if pos == -1:
|
||||
object_id = long(path)
|
||||
object_id = int(path)
|
||||
else:
|
||||
object_id = long(path[0:pos])
|
||||
object_id = int(path[0:pos])
|
||||
except ValueError:
|
||||
raise Http404(
|
||||
"No ct_id parameter, unable to find admin subclass for path '{0}'.".format(
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
"""
|
||||
PolymorphicModel Meta Class
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
import inspect
|
||||
import os
|
||||
import sys
|
||||
|
|
|
|||
|
|
@ -1,22 +1,4 @@
|
|||
"""Compatibility with Python 2 (taken from 'django.utils.six')"""
|
||||
import sys
|
||||
|
||||
PY2 = sys.version_info[0] == 2
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
|
||||
if PY3:
|
||||
string_types = (str,)
|
||||
integer_types = (int,)
|
||||
class_types = (type,)
|
||||
text_type = str
|
||||
binary_type = bytes
|
||||
|
||||
MAXSIZE = sys.maxsize
|
||||
else:
|
||||
string_types = (basestring,)
|
||||
integer_types = (int, long)
|
||||
|
||||
|
||||
def with_metaclass(meta, *bases):
|
||||
class metaclass(type):
|
||||
|
|
@ -24,22 +6,3 @@ def with_metaclass(meta, *bases):
|
|||
return meta(name, bases, d)
|
||||
|
||||
return type.__new__(metaclass, "temporary_class", (), {})
|
||||
|
||||
|
||||
def python_2_unicode_compatible(klass):
|
||||
"""
|
||||
A decorator that defines __unicode__ and __str__ methods under Python 2.
|
||||
Under Python 3 it does nothing.
|
||||
|
||||
To support Python 2 and 3 with a single code base, define a __str__ method
|
||||
returning text and apply this decorator to the class.
|
||||
"""
|
||||
if PY2:
|
||||
if "__str__" not in klass.__dict__:
|
||||
raise ValueError(
|
||||
"@python_2_unicode_compatible cannot be applied "
|
||||
"to %s because it doesn't define __str__()." % klass.__name__
|
||||
)
|
||||
klass.__unicode__ = klass.__str__
|
||||
klass.__str__ = lambda self: self.__unicode__().encode("utf-8")
|
||||
return klass
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ The ``extra_views.advanced`` provides a method to combine that with a create/upd
|
|||
|
||||
This package provides classes that support both options for polymorphic formsets.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
import extra_views
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
|
|
|
|||
|
|
@ -2,17 +2,14 @@
|
|||
"""
|
||||
The manager class for use in the models.
|
||||
"""
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models
|
||||
|
||||
from polymorphic.compat import python_2_unicode_compatible
|
||||
from polymorphic.query import PolymorphicQuerySet
|
||||
|
||||
__all__ = ("PolymorphicManager", "PolymorphicQuerySet")
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class PolymorphicManager(models.Manager):
|
||||
"""
|
||||
Manager for PolymorphicModel
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
"""
|
||||
Seamless Polymorphic Inheritance for Django Models
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db import models
|
||||
from django.db.models.fields.related import (
|
||||
|
|
|
|||
|
|
@ -2,13 +2,11 @@
|
|||
"""
|
||||
QuerySet for PolymorphicModel
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
import copy
|
||||
from collections import defaultdict
|
||||
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db.models import FieldDoesNotExist
|
||||
from django.core.exceptions import FieldDoesNotExist
|
||||
from django.db.models.query import ModelIterable, Q, QuerySet
|
||||
|
||||
from . import compat
|
||||
|
|
@ -177,7 +175,7 @@ class PolymorphicQuerySet(QuerySet):
|
|||
"""translate the field paths in the args, then call vanilla order_by."""
|
||||
field_names = [
|
||||
translate_polymorphic_field_path(self.model, a)
|
||||
if isinstance(a, compat.string_types)
|
||||
if isinstance(a, str)
|
||||
else a # allow expressions to pass unchanged
|
||||
for a in field_names
|
||||
]
|
||||
|
|
|
|||
|
|
@ -2,14 +2,12 @@
|
|||
"""
|
||||
PolymorphicQuerySet support functions
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
import copy
|
||||
from collections import deque
|
||||
|
||||
from django.apps import apps
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import FieldError
|
||||
from django.core.exceptions import FieldError, FieldDoesNotExist
|
||||
from django.db import models
|
||||
from django.db.models import Q
|
||||
from django.db.models.fields.related import ForeignObjectRel, RelatedField
|
||||
|
|
@ -144,7 +142,7 @@ def translate_polymorphic_field_path(queryset_model, field_path):
|
|||
into modela__modelb__modelc__field3.
|
||||
Returns: translated path (unchanged, if no translation needed)
|
||||
"""
|
||||
if not isinstance(field_path, compat.string_types):
|
||||
if not isinstance(field_path, str):
|
||||
raise ValueError("Expected field name as string: {0}".format(field_path))
|
||||
|
||||
classname, sep, pure_field_path = field_path.partition("___")
|
||||
|
|
@ -189,7 +187,7 @@ def translate_polymorphic_field_path(queryset_model, field_path):
|
|||
# Can also test whether the field exists in the related object to avoid ambiguity between
|
||||
# class names and field names, but that never happens when your class names are in CamelCase.
|
||||
return field_path # No exception raised, field does exist.
|
||||
except models.FieldDoesNotExist:
|
||||
except FieldDoesNotExist:
|
||||
pass
|
||||
|
||||
submodels = _get_all_sub_models(queryset_model)
|
||||
|
|
|
|||
|
|
@ -4,12 +4,10 @@ import re
|
|||
from django.db import models
|
||||
|
||||
from . import compat
|
||||
from .compat import python_2_unicode_compatible
|
||||
|
||||
RE_DEFERRED = re.compile("_Deferred_.*")
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class ShowFieldBase(object):
|
||||
""" base class for the ShowField... model mixins, does the work """
|
||||
|
||||
|
|
@ -42,7 +40,7 @@ class ShowFieldBase(object):
|
|||
out += content.__class__.__name__
|
||||
elif issubclass(field_type, models.ManyToManyField):
|
||||
out += "%d" % content.count()
|
||||
elif isinstance(content, compat.integer_types):
|
||||
elif isinstance(content, int):
|
||||
out += str(content)
|
||||
elif content is None:
|
||||
out += "None"
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class BreadcrumbScope(Node):
|
|||
# Instead, have an assignment tag that inserts that in the template.
|
||||
base_opts = self.base_opts.resolve(context)
|
||||
new_vars = {}
|
||||
if base_opts and not isinstance(base_opts, compat.string_types):
|
||||
if base_opts and not isinstance(base_opts, str):
|
||||
new_vars = {
|
||||
"app_label": base_opts.app_label, # What this is all about
|
||||
"opts": base_opts,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from __future__ import print_function
|
||||
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db.models import Q
|
||||
from django.test import TestCase
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import sys
|
||||
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db import DEFAULT_DB_ALIAS
|
||||
|
||||
|
|
@ -59,12 +57,9 @@ def sort_by_subclass(*classes):
|
|||
"""
|
||||
Sort a series of models by their inheritance order.
|
||||
"""
|
||||
if sys.version_info[0] == 2:
|
||||
return sorted(classes, cmp=_compare_mro)
|
||||
else:
|
||||
from functools import cmp_to_key
|
||||
from functools import cmp_to_key
|
||||
|
||||
return sorted(classes, key=cmp_to_key(_compare_mro))
|
||||
return sorted(classes, key=cmp_to_key(_compare_mro))
|
||||
|
||||
|
||||
def get_base_polymorphic_model(ChildModel, allow_abstract=False):
|
||||
|
|
|
|||
|
|
@ -14,18 +14,19 @@ classifiers =
|
|||
Development Status :: 5 - Production/Stable
|
||||
Environment :: Web Environment
|
||||
Framework :: Django
|
||||
Framework :: Django :: 1.11
|
||||
Framework :: Django :: 2.0
|
||||
Framework :: Django :: 2.1
|
||||
Framework :: Django :: 2.2
|
||||
Framework :: Django :: 3.0
|
||||
Framework :: Django :: 3.1
|
||||
Intended Audience :: Developers
|
||||
License :: OSI Approved :: BSD License
|
||||
Operating System :: OS Independent
|
||||
Programming Language :: Python :: 2.7
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3 :: Only
|
||||
Programming Language :: Python :: 3.5
|
||||
Programming Language :: Python :: 3.6
|
||||
Programming Language :: Python :: 3.7
|
||||
Programming Language :: Python :: 3.8
|
||||
Topic :: Database
|
||||
|
||||
[options]
|
||||
|
|
|
|||
12
tox.ini
12
tox.ini
|
|
@ -1,9 +1,9 @@
|
|||
[tox]
|
||||
envlist =
|
||||
py27-django{111}
|
||||
py35-django{111,20}
|
||||
py36-django{111,20,21,22,master}
|
||||
py37-django{21,22,master}
|
||||
py35-django{21,22,master}
|
||||
py36-django{21,22,30,31,master}
|
||||
py37-django{21,22,30,31,master}
|
||||
py38-django{21,22,30,31,master}
|
||||
docs
|
||||
|
||||
[testenv]
|
||||
|
|
@ -14,10 +14,10 @@ setenv =
|
|||
deps =
|
||||
coverage
|
||||
dj-database-url
|
||||
django111: Django >= 1.11, < 2.0
|
||||
django20: Django ~= 2.0
|
||||
django21: Django ~= 2.1
|
||||
django22: Django ~= 2.2
|
||||
django30: Django ~= 3.0
|
||||
django31: Django ~= 3.1
|
||||
djangomaster: https://github.com/django/django/archive/master.tar.gz
|
||||
postgres: psycopg2
|
||||
commands =
|
||||
|
|
|
|||
Loading…
Reference in New Issue