Drop support for Django <1.8, Python <2.7
parent
df0041dff6
commit
298460c4cf
|
|
@ -2,22 +2,16 @@
|
||||||
Automatically mention all model fields as parameters in the model construction.
|
Automatically mention all model fields as parameters in the model construction.
|
||||||
Based on http://djangosnippets.org/snippets/2533/
|
Based on http://djangosnippets.org/snippets/2533/
|
||||||
"""
|
"""
|
||||||
import django
|
|
||||||
from django.utils.html import strip_tags
|
|
||||||
from django.utils.encoding import force_text
|
|
||||||
import inspect
|
import inspect
|
||||||
|
from django.utils.encoding import force_text
|
||||||
|
from django.utils.html import strip_tags
|
||||||
|
|
||||||
|
|
||||||
def improve_model_docstring(app, what, name, obj, options, lines):
|
def improve_model_docstring(app, what, name, obj, options, lines):
|
||||||
from django.db import models # must be inside the function, to allow settings initialization first.
|
from django.db import models # must be inside the function, to allow settings initialization first.
|
||||||
|
|
||||||
if inspect.isclass(obj) and issubclass(obj, models.Model):
|
if inspect.isclass(obj) and issubclass(obj, models.Model):
|
||||||
if django.VERSION >= (1,8):
|
model_fields = obj._meta.get_fields()
|
||||||
model_fields = obj._meta.get_fields()
|
|
||||||
elif django.VERSION >= (1,6):
|
|
||||||
model_fields = obj._meta.fields
|
|
||||||
else:
|
|
||||||
model_fields = obj._meta._fields()
|
|
||||||
|
|
||||||
for field in model_fields:
|
for field in model_fields:
|
||||||
help_text = strip_tags(force_text(field.help_text))
|
help_text = strip_tags(force_text(field.help_text))
|
||||||
|
|
@ -39,9 +33,9 @@ def improve_model_docstring(app, what, name, obj, options, lines):
|
||||||
# Return the extended docstring
|
# Return the extended docstring
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
|
|
||||||
# Allow this module to be used as sphinx extension:
|
# Allow this module to be used as sphinx extension:
|
||||||
def setup(app):
|
def setup(app):
|
||||||
# Generate docstrings for Django model fields
|
# Generate docstrings for Django model fields
|
||||||
# Register the docstring processor with sphinx
|
# Register the docstring processor with sphinx
|
||||||
app.connect('autodoc-process-docstring', improve_model_docstring)
|
app.connect('autodoc-process-docstring', improve_model_docstring)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,7 @@ sys.path.insert(0, os.path.abspath('_ext'))
|
||||||
sys.path.insert(0, os.path.abspath('..'))
|
sys.path.insert(0, os.path.abspath('..'))
|
||||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'djangodummy.settings'
|
os.environ['DJANGO_SETTINGS_MODULE'] = 'djangodummy.settings'
|
||||||
|
|
||||||
if django.VERSION >= (1, 8):
|
django.setup()
|
||||||
django.setup()
|
|
||||||
|
|
||||||
# -- General configuration -----------------------------------------------------
|
# -- General configuration -----------------------------------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,6 @@ Django as automatic manager for several purposes, including accessing
|
||||||
related objects. It must not filter objects and it's safest to use
|
related objects. It must not filter objects and it's safest to use
|
||||||
the plain ``PolymorphicManager`` here.
|
the plain ``PolymorphicManager`` here.
|
||||||
|
|
||||||
Note that get_query_set is deprecated in Django 1.8 and creates warnings in Django 1.7.
|
|
||||||
|
|
||||||
Manager Inheritance
|
Manager Inheritance
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
|
@ -69,8 +67,6 @@ regarding their start time and ``ArtProject.objects_ordered.most_recent()``
|
||||||
will return the ten most recent art projects.
|
will return the ten most recent art projects.
|
||||||
.
|
.
|
||||||
|
|
||||||
Note that get_query_set is deprecated in Django 1.8 and creates warnings in Django 1.7.
|
|
||||||
|
|
||||||
Using a Custom Queryset Class
|
Using a Custom Queryset Class
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import django
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
|
|
@ -67,7 +66,6 @@ INSTALLED_APPS = (
|
||||||
'django.contrib.admin',
|
'django.contrib.admin',
|
||||||
'django.contrib.contenttypes',
|
'django.contrib.contenttypes',
|
||||||
'django.contrib.sessions',
|
'django.contrib.sessions',
|
||||||
#'django.contrib.sites',
|
|
||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
|
|
||||||
|
|
@ -76,8 +74,7 @@ INSTALLED_APPS = (
|
||||||
'orders',
|
'orders',
|
||||||
)
|
)
|
||||||
|
|
||||||
if django.VERSION >= (1, 7):
|
TEST_RUNNER = 'django.test.runner.DiscoverRunner' # silence system checks
|
||||||
TEST_RUNNER = 'django.test.runner.DiscoverRunner' # silence system checks
|
|
||||||
|
|
||||||
# Logging configuration
|
# Logging configuration
|
||||||
LOGGING = {
|
LOGGING = {
|
||||||
|
|
|
||||||
|
|
@ -3,34 +3,32 @@
|
||||||
This module is a scratchpad for general development, testing & debugging
|
This module is a scratchpad for general development, testing & debugging
|
||||||
Well, even more so than pcmd.py. You best ignore p2cmd.py.
|
Well, even more so than pcmd.py. You best ignore p2cmd.py.
|
||||||
"""
|
"""
|
||||||
from django.core.management.base import NoArgsCommand
|
|
||||||
from pprint import pprint
|
|
||||||
import time
|
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
|
from pprint import pprint
|
||||||
|
from random import Random
|
||||||
|
from django.core.management.base import NoArgsCommand
|
||||||
|
from django.db import connection
|
||||||
|
|
||||||
from pexp.models import *
|
from pexp.models import *
|
||||||
|
|
||||||
|
|
||||||
def reset_queries():
|
rnd = Random()
|
||||||
if django.VERSION < (1, 8):
|
|
||||||
connection.queries = []
|
|
||||||
else:
|
|
||||||
connection.queries_log.clear()
|
|
||||||
|
|
||||||
|
|
||||||
def show_queries():
|
def show_queries():
|
||||||
print
|
print()
|
||||||
print 'QUERIES:', len(connection.queries)
|
print("QUERIES:", len(connection.queries))
|
||||||
pprint(connection.queries)
|
pprint(connection.queries)
|
||||||
print
|
print()
|
||||||
connection.queries = []
|
connection.queries = []
|
||||||
|
|
||||||
|
|
||||||
def print_timing(func, message='', iterations=1):
|
def print_timing(func, message='', iterations=1):
|
||||||
def wrapper(*arg):
|
def wrapper(*arg):
|
||||||
results = []
|
results = []
|
||||||
reset_queries()
|
connection.queries_log.clear()
|
||||||
for i in xrange(iterations):
|
for i in range(iterations):
|
||||||
t1 = time.time()
|
t1 = time.time()
|
||||||
x = func(*arg)
|
x = func(*arg)
|
||||||
t2 = time.time()
|
t2 = time.time()
|
||||||
|
|
@ -38,13 +36,12 @@ def print_timing(func, message='', iterations=1):
|
||||||
res_sum = 0
|
res_sum = 0
|
||||||
for r in results:
|
for r in results:
|
||||||
res_sum += r
|
res_sum += r
|
||||||
median = res_sum / len(results)
|
print("%s%-19s: %.4f ms, %i queries (%i times)" % (
|
||||||
print '%s%-19s: %.4f ms, %i queries (%i times)' % (
|
|
||||||
message, func.func_name,
|
message, func.func_name,
|
||||||
res_sum,
|
res_sum,
|
||||||
len(connection.queries),
|
len(connection.queries),
|
||||||
iterations
|
iterations
|
||||||
)
|
))
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
@ -58,18 +55,18 @@ class Command(NoArgsCommand):
|
||||||
a = TestModelA.objects.create(field1='A1')
|
a = TestModelA.objects.create(field1='A1')
|
||||||
b = TestModelB.objects.create(field1='B1', field2='B2')
|
b = TestModelB.objects.create(field1='B1', field2='B2')
|
||||||
c = TestModelC.objects.create(field1='C1', field2='C2', field3='C3')
|
c = TestModelC.objects.create(field1='C1', field2='C2', field3='C3')
|
||||||
reset_queries()
|
connection.queries_log.clear()
|
||||||
print TestModelC.base_objects.all()
|
print(TestModelC.base_objects.all())
|
||||||
show_queries()
|
show_queries()
|
||||||
|
|
||||||
if False:
|
if False:
|
||||||
TestModelA.objects.all().delete()
|
TestModelA.objects.all().delete()
|
||||||
for i in xrange(1000):
|
for i in range(1000):
|
||||||
a = TestModelA.objects.create(field1=str(i % 100))
|
a = TestModelA.objects.create(field1=str(i % 100))
|
||||||
b = TestModelB.objects.create(field1=str(i % 100), field2=str(i % 200))
|
b = TestModelB.objects.create(field1=str(i % 100), field2=str(i % 200))
|
||||||
c = TestModelC.objects.create(field1=str(i % 100), field2=str(i % 200), field3=str(i % 300))
|
c = TestModelC.objects.create(field1=str(i % 100), field2=str(i % 200), field3=str(i % 300))
|
||||||
if i % 100 == 0:
|
if i % 100 == 0:
|
||||||
print i
|
print(i)
|
||||||
|
|
||||||
f = print_timing(poly_sql_query, iterations=1000)
|
f = print_timing(poly_sql_query, iterations=1000)
|
||||||
f()
|
f()
|
||||||
|
|
@ -85,11 +82,7 @@ class Command(NoArgsCommand):
|
||||||
c = NormalModelC.objects.create(field1='C1', field2='C2', field3='C3')
|
c = NormalModelC.objects.create(field1='C1', field2='C2', field3='C3')
|
||||||
qs = TestModelA.objects.raw("SELECT * from pexp_testmodela")
|
qs = TestModelA.objects.raw("SELECT * from pexp_testmodela")
|
||||||
for o in list(qs):
|
for o in list(qs):
|
||||||
print o
|
print(o)
|
||||||
|
|
||||||
from django.db import connection, transaction
|
|
||||||
from random import Random
|
|
||||||
rnd = Random()
|
|
||||||
|
|
||||||
|
|
||||||
def poly_sql_query():
|
def poly_sql_query():
|
||||||
|
|
@ -103,7 +96,7 @@ def poly_sql_query():
|
||||||
ON pexp_testmodelb.testmodela_ptr_id = pexp_testmodelc.testmodelb_ptr_id
|
ON pexp_testmodelb.testmodela_ptr_id = pexp_testmodelc.testmodelb_ptr_id
|
||||||
WHERE pexp_testmodela.field1=%i
|
WHERE pexp_testmodela.field1=%i
|
||||||
ORDER BY pexp_testmodela.id
|
ORDER BY pexp_testmodela.id
|
||||||
""" % rnd.randint(0, 100) )
|
""" % rnd.randint(0, 100))
|
||||||
# row=cursor.fetchone()
|
# row=cursor.fetchone()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -115,6 +108,6 @@ def poly_sql_query2():
|
||||||
FROM pexp_testmodela
|
FROM pexp_testmodela
|
||||||
WHERE pexp_testmodela.field1=%i
|
WHERE pexp_testmodela.field1=%i
|
||||||
ORDER BY pexp_testmodela.id
|
ORDER BY pexp_testmodela.id
|
||||||
""" % rnd.randint(0, 100) )
|
""" % rnd.randint(0, 100))
|
||||||
# row=cursor.fetchone()
|
# row=cursor.fetchone()
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -3,30 +3,25 @@
|
||||||
This module is a scratchpad for general development, testing & debugging
|
This module is a scratchpad for general development, testing & debugging
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import time
|
||||||
|
import sys
|
||||||
|
|
||||||
from django.core.management.base import NoArgsCommand
|
from django.core.management.base import NoArgsCommand
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
import sys
|
|
||||||
from pexp.models import *
|
from pexp.models import *
|
||||||
|
|
||||||
|
|
||||||
num_objects = 1000
|
num_objects = 1000
|
||||||
|
|
||||||
|
|
||||||
def reset_queries():
|
|
||||||
if django.VERSION < (1, 8):
|
|
||||||
connection.queries = []
|
|
||||||
else:
|
|
||||||
connection.queries_log.clear()
|
|
||||||
|
|
||||||
|
|
||||||
def show_queries():
|
def show_queries():
|
||||||
print
|
print()
|
||||||
print 'QUERIES:', len(connection.queries)
|
print("QUERIES:", len(connection.queries))
|
||||||
pprint(connection.queries)
|
pprint(connection.queries)
|
||||||
print
|
print()
|
||||||
reset_queries()
|
connection.queries_log.clear()
|
||||||
|
|
||||||
import time
|
|
||||||
|
|
||||||
###################################################################################
|
###################################################################################
|
||||||
# benchmark wrappers
|
# benchmark wrappers
|
||||||
|
|
@ -35,8 +30,8 @@ import time
|
||||||
def print_timing(func, message='', iterations=1):
|
def print_timing(func, message='', iterations=1):
|
||||||
def wrapper(*arg):
|
def wrapper(*arg):
|
||||||
results = []
|
results = []
|
||||||
reset_queries()
|
connection.queries_log.clear()
|
||||||
for i in xrange(iterations):
|
for i in range(iterations):
|
||||||
t1 = time.time()
|
t1 = time.time()
|
||||||
x = func(*arg)
|
x = func(*arg)
|
||||||
t2 = time.time()
|
t2 = time.time()
|
||||||
|
|
@ -45,11 +40,11 @@ def print_timing(func, message='', iterations=1):
|
||||||
for r in results:
|
for r in results:
|
||||||
res_sum += r
|
res_sum += r
|
||||||
median = res_sum / len(results)
|
median = res_sum / len(results)
|
||||||
print '%s%-19s: %.0f ms, %i queries' % (
|
print("%s%-19s: %.0f ms, %i queries" % (
|
||||||
message, func.func_name,
|
message, func.func_name,
|
||||||
median,
|
median,
|
||||||
len(connection.queries) / len(results)
|
len(connection.queries) / len(results)
|
||||||
)
|
))
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import django
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
from polymorphic.models import PolymorphicModel
|
from polymorphic.models import PolymorphicModel
|
||||||
|
|
@ -20,15 +19,9 @@ class ResearchProject(Project):
|
||||||
supervisor = models.CharField(max_length=30)
|
supervisor = models.CharField(max_length=30)
|
||||||
|
|
||||||
|
|
||||||
if django.VERSION < (1, 8):
|
|
||||||
from polymorphic.tools_for_tests import UUIDField
|
|
||||||
else:
|
|
||||||
from django.db.models import UUIDField
|
|
||||||
|
|
||||||
|
|
||||||
class UUIDModelA(ShowFieldTypeAndContent, PolymorphicModel):
|
class UUIDModelA(ShowFieldTypeAndContent, PolymorphicModel):
|
||||||
"""UUID as primary key example"""
|
"""UUID as primary key example"""
|
||||||
uuid_primary_key = UUIDField(primary_key=True)
|
uuid_primary_key = models.UUIDField(primary_key=True)
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,36 +6,6 @@ Copyright:
|
||||||
This code and affiliated files are (C) by Bert Constantin and individual contributors.
|
This code and affiliated files are (C) by Bert Constantin and individual contributors.
|
||||||
Please see LICENSE and AUTHORS for more information.
|
Please see LICENSE and AUTHORS for more information.
|
||||||
"""
|
"""
|
||||||
import django
|
|
||||||
|
|
||||||
# See PEP 440 (https://www.python.org/dev/peps/pep-0440/)
|
# See PEP 440 (https://www.python.org/dev/peps/pep-0440/)
|
||||||
__version__ = "1.2"
|
__version__ = "1.2"
|
||||||
|
|
||||||
|
|
||||||
# Monkey-patch Django < 1.5 to allow ContentTypes for proxy models.
|
|
||||||
if django.VERSION[:2] < (1, 5):
|
|
||||||
from django.contrib.contenttypes.models import ContentTypeManager
|
|
||||||
from django.utils.encoding import smart_text
|
|
||||||
|
|
||||||
def get_for_model(self, model, for_concrete_model=True):
|
|
||||||
if for_concrete_model:
|
|
||||||
model = model._meta.concrete_model
|
|
||||||
elif model._deferred:
|
|
||||||
model = model._meta.proxy_for_model
|
|
||||||
|
|
||||||
opts = model._meta
|
|
||||||
|
|
||||||
try:
|
|
||||||
ct = self._get_from_cache(opts)
|
|
||||||
except KeyError:
|
|
||||||
ct, created = self.get_or_create(
|
|
||||||
app_label=opts.app_label,
|
|
||||||
model=opts.object_name.lower(),
|
|
||||||
defaults={'name': smart_text(opts.verbose_name_raw)},
|
|
||||||
)
|
|
||||||
self._add_to_cache(self.db, ct)
|
|
||||||
|
|
||||||
return ct
|
|
||||||
|
|
||||||
ContentTypeManager.get_for_model__original = ContentTypeManager.get_for_model
|
|
||||||
ContentTypeManager.get_for_model = get_for_model
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,10 @@
|
||||||
|
from django.contrib.contenttypes.admin import GenericInlineModelAdmin
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
|
|
||||||
from polymorphic.formsets import polymorphic_child_forms_factory, BaseGenericPolymorphicInlineFormSet, GenericPolymorphicFormSetChild
|
from polymorphic.formsets import polymorphic_child_forms_factory, BaseGenericPolymorphicInlineFormSet, GenericPolymorphicFormSetChild
|
||||||
from .inlines import PolymorphicInlineModelAdmin
|
from .inlines import PolymorphicInlineModelAdmin
|
||||||
|
|
||||||
try:
|
|
||||||
from django.contrib.contenttypes.admin import GenericInlineModelAdmin # Django 1.7+
|
|
||||||
except ImportError:
|
|
||||||
from django.contrib.contenttypes.generic import GenericInlineModelAdmin
|
|
||||||
|
|
||||||
|
|
||||||
class GenericPolymorphicInlineModelAdmin(PolymorphicInlineModelAdmin, GenericInlineModelAdmin):
|
class GenericPolymorphicInlineModelAdmin(PolymorphicInlineModelAdmin, GenericInlineModelAdmin):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ Each row in the inline can correspond with a different subclass.
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from django.contrib.admin.options import InlineModelAdmin
|
from django.contrib.admin.options import InlineModelAdmin
|
||||||
|
from django.contrib.admin.utils import flatten_fieldsets
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.forms import Media
|
from django.forms import Media
|
||||||
|
|
||||||
|
|
@ -13,11 +14,6 @@ from polymorphic.formsets import polymorphic_child_forms_factory, BasePolymorphi
|
||||||
from polymorphic.formsets.utils import add_media
|
from polymorphic.formsets.utils import add_media
|
||||||
from .helpers import PolymorphicInlineSupportMixin
|
from .helpers import PolymorphicInlineSupportMixin
|
||||||
|
|
||||||
try:
|
|
||||||
from django.contrib.admin.utils import flatten_fieldsets # Django 1.7+
|
|
||||||
except ImportError:
|
|
||||||
from django.contrib.admin.util import flatten_fieldsets
|
|
||||||
|
|
||||||
|
|
||||||
class PolymorphicInlineModelAdmin(InlineModelAdmin):
|
class PolymorphicInlineModelAdmin(InlineModelAdmin):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,18 @@
|
||||||
"""
|
"""
|
||||||
The parent admin displays the list view of the base model.
|
The parent admin displays the list view of the base model.
|
||||||
"""
|
"""
|
||||||
import sys
|
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
import django
|
import django
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.admin.helpers import AdminErrorList, AdminForm
|
from django.contrib.admin.helpers import AdminErrorList, AdminForm
|
||||||
|
from django.contrib.admin.templatetags.admin_urls import add_preserved_filters
|
||||||
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.core.urlresolvers import RegexURLResolver
|
from django.core.urlresolvers import RegexURLResolver
|
||||||
from django.http import Http404, HttpResponseRedirect
|
from django.http import Http404, HttpResponseRedirect
|
||||||
from django.shortcuts import render_to_response
|
from django.template.response import TemplateResponse
|
||||||
from django.template.context import RequestContext
|
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
from django.utils.http import urlencode
|
from django.utils.http import urlencode
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
|
@ -21,16 +20,6 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from .forms import PolymorphicModelChoiceForm
|
from .forms import PolymorphicModelChoiceForm
|
||||||
|
|
||||||
try:
|
|
||||||
# Django 1.6 implements this
|
|
||||||
from django.contrib.admin.templatetags.admin_urls import add_preserved_filters
|
|
||||||
except ImportError:
|
|
||||||
def add_preserved_filters(context, form_url):
|
|
||||||
return form_url
|
|
||||||
|
|
||||||
if sys.version_info[0] >= 3:
|
|
||||||
long = int
|
|
||||||
|
|
||||||
|
|
||||||
class RegistrationClosed(RuntimeError):
|
class RegistrationClosed(RuntimeError):
|
||||||
"The admin model can't be registered anymore at this point."
|
"The admin model can't be registered anymore at this point."
|
||||||
|
|
@ -210,13 +199,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
||||||
qs = qs.non_polymorphic()
|
qs = qs.non_polymorphic()
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
# For Django 1.5:
|
|
||||||
def queryset(self, request):
|
|
||||||
qs = super(PolymorphicParentModelAdmin, self).queryset(request)
|
|
||||||
if not self.polymorphic_list:
|
|
||||||
qs = qs.non_polymorphic()
|
|
||||||
return qs
|
|
||||||
|
|
||||||
def add_view(self, request, form_url='', extra_context=None):
|
def add_view(self, request, form_url='', extra_context=None):
|
||||||
"""Redirect the add view to the real admin."""
|
"""Redirect the add view to the real admin."""
|
||||||
ct_id = int(request.GET.get('ct_id', 0))
|
ct_id = int(request.GET.get('ct_id', 0))
|
||||||
|
|
@ -238,17 +220,16 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
||||||
real_admin = self._get_real_admin(object_id)
|
real_admin = self._get_real_admin(object_id)
|
||||||
return real_admin.change_view(request, object_id, *args, **kwargs)
|
return real_admin.change_view(request, object_id, *args, **kwargs)
|
||||||
|
|
||||||
if django.VERSION >= (1, 7):
|
def changeform_view(self, request, object_id=None, *args, **kwargs):
|
||||||
def changeform_view(self, request, object_id=None, *args, **kwargs):
|
# The `changeform_view` is available as of Django 1.7, combining the add_view and change_view.
|
||||||
# The `changeform_view` is available as of Django 1.7, combining the add_view and change_view.
|
# As it's directly called by django-reversion, this method is also overwritten to make sure it
|
||||||
# As it's directly called by django-reversion, this method is also overwritten to make sure it
|
# also redirects to the child admin.
|
||||||
# also redirects to the child admin.
|
if object_id:
|
||||||
if object_id:
|
real_admin = self._get_real_admin(object_id)
|
||||||
real_admin = self._get_real_admin(object_id)
|
return real_admin.changeform_view(request, object_id, *args, **kwargs)
|
||||||
return real_admin.changeform_view(request, object_id, *args, **kwargs)
|
else:
|
||||||
else:
|
# Add view. As it should already be handled via `add_view`, this means something custom is done here!
|
||||||
# Add view. As it should already be handled via `add_view`, this means something custom is done here!
|
return super(PolymorphicParentModelAdmin, self).changeform_view(request, object_id, *args, **kwargs)
|
||||||
return super(PolymorphicParentModelAdmin, self).changeform_view(request, object_id, *args, **kwargs)
|
|
||||||
|
|
||||||
def history_view(self, request, object_id, extra_context=None):
|
def history_view(self, request, object_id, extra_context=None):
|
||||||
"""Redirect the history view to the real admin."""
|
"""Redirect the history view to the real admin."""
|
||||||
|
|
@ -334,9 +315,9 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
||||||
try:
|
try:
|
||||||
pos = path.find('/')
|
pos = path.find('/')
|
||||||
if pos == -1:
|
if pos == -1:
|
||||||
object_id = long(path)
|
object_id = int(path)
|
||||||
else:
|
else:
|
||||||
object_id = long(path[0:pos])
|
object_id = int(path[0:pos])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise Http404("No ct_id parameter, unable to find admin subclass for path '{0}'.".format(path))
|
raise Http404("No ct_id parameter, unable to find admin subclass for path '{0}'.".format(path))
|
||||||
|
|
||||||
|
|
@ -407,8 +388,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
||||||
'add': True,
|
'add': True,
|
||||||
'save_on_top': self.save_on_top,
|
'save_on_top': self.save_on_top,
|
||||||
})
|
})
|
||||||
if hasattr(self.admin_site, 'root_path'):
|
|
||||||
context['root_path'] = self.admin_site.root_path # Django < 1.4
|
|
||||||
|
|
||||||
templates = self.add_type_template or [
|
templates = self.add_type_template or [
|
||||||
"admin/%s/%s/add_type_form.html" % (app_label, opts.object_name.lower()),
|
"admin/%s/%s/add_type_form.html" % (app_label, opts.object_name.lower()),
|
||||||
|
|
@ -417,13 +396,8 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
||||||
"admin/add_type_form.html"
|
"admin/add_type_form.html"
|
||||||
]
|
]
|
||||||
|
|
||||||
if django.VERSION >= (1, 8):
|
request.current_app = self.admin_site.name
|
||||||
from django.template.response import TemplateResponse
|
return TemplateResponse(request, templates, context)
|
||||||
request.current_app = self.admin_site.name
|
|
||||||
return TemplateResponse(request, templates, context)
|
|
||||||
else:
|
|
||||||
context_instance = RequestContext(request, current_app=self.admin_site.name)
|
|
||||||
return render_to_response(templates, context, context_instance=context_instance)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def change_list_template(self):
|
def change_list_template(self):
|
||||||
|
|
@ -445,7 +419,4 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
def _get_opt(model):
|
def _get_opt(model):
|
||||||
try:
|
return model._meta.app_label, model._meta.model_name
|
||||||
return model._meta.app_label, model._meta.model_name # Django 1.7 format
|
|
||||||
except AttributeError:
|
|
||||||
return model._meta.app_label, model._meta.module_name
|
|
||||||
|
|
|
||||||
|
|
@ -132,6 +132,17 @@ class PolymorphicModelBase(ModelBase):
|
||||||
if type(manager) == models.manager.ManagerDescriptor:
|
if type(manager) == models.manager.ManagerDescriptor:
|
||||||
manager = manager.manager
|
manager = manager.manager
|
||||||
|
|
||||||
|
# As of Django 1.5, the abstract models don't get any managers, only a
|
||||||
|
# AbstractManagerDescriptor as substitute.
|
||||||
|
if type(manager) == AbstractManagerDescriptor and base.__name__ == 'PolymorphicModel':
|
||||||
|
model = manager.model
|
||||||
|
if key == 'objects':
|
||||||
|
manager = PolymorphicManager()
|
||||||
|
manager.model = model
|
||||||
|
elif key == 'base_objects':
|
||||||
|
manager = models.Manager()
|
||||||
|
manager.model = model
|
||||||
|
|
||||||
if AbstractManagerDescriptor is not None:
|
if AbstractManagerDescriptor is not None:
|
||||||
# Django 1.4 unconditionally assigned managers to a model. As of Django 1.5 however,
|
# Django 1.4 unconditionally assigned managers to a model. As of Django 1.5 however,
|
||||||
# the abstract models don't get any managers, only a AbstractManagerDescriptor as substitute.
|
# the abstract models don't get any managers, only a AbstractManagerDescriptor as substitute.
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,11 @@
|
||||||
import django
|
import django
|
||||||
|
from django.contrib.contenttypes.forms import BaseGenericInlineFormSet, generic_inlineformset_factory
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.forms.models import ModelForm
|
from django.forms.models import ModelForm
|
||||||
|
|
||||||
from .models import BasePolymorphicModelFormSet, polymorphic_child_forms_factory, PolymorphicFormSetChild
|
from .models import BasePolymorphicModelFormSet, polymorphic_child_forms_factory, PolymorphicFormSetChild
|
||||||
|
|
||||||
try:
|
|
||||||
from django.contrib.contenttypes.forms import BaseGenericInlineFormSet, generic_inlineformset_factory # Django 1.7+
|
|
||||||
except ImportError:
|
|
||||||
from django.contrib.contenttypes.generic import BaseGenericInlineFormSet, generic_inlineformset_factory
|
|
||||||
|
|
||||||
|
|
||||||
class GenericPolymorphicFormSetChild(PolymorphicFormSetChild):
|
class GenericPolymorphicFormSetChild(PolymorphicFormSetChild):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
import django
|
import django
|
||||||
from django import forms
|
from django import forms
|
||||||
|
|
@ -7,11 +8,6 @@ from django.forms.models import ModelForm, BaseModelFormSet, BaseInlineFormSet,
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from .utils import add_media
|
from .utils import add_media
|
||||||
|
|
||||||
try:
|
|
||||||
from collections import OrderedDict
|
|
||||||
except ImportError:
|
|
||||||
from django.utils.datastructures import SortedDict as OrderedDict # Python 2.6
|
|
||||||
|
|
||||||
|
|
||||||
class PolymorphicFormSetChild(object):
|
class PolymorphicFormSetChild(object):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,10 @@ The manager class for use in the models.
|
||||||
"""
|
"""
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import warnings
|
import warnings
|
||||||
import django
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.utils.six import python_2_unicode_compatible
|
||||||
from polymorphic.query import PolymorphicQuerySet
|
from polymorphic.query import PolymorphicQuerySet
|
||||||
|
|
||||||
try:
|
|
||||||
from django.utils.six import python_2_unicode_compatible
|
|
||||||
except ImportError:
|
|
||||||
from django.utils.encoding import python_2_unicode_compatible # Django 1.5
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'PolymorphicManager',
|
'PolymorphicManager',
|
||||||
|
|
@ -32,6 +27,12 @@ class PolymorphicManager(models.Manager):
|
||||||
use_for_related_fields = True
|
use_for_related_fields = True
|
||||||
queryset_class = PolymorphicQuerySet
|
queryset_class = PolymorphicQuerySet
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_queryset(cls, queryset_class, class_name=None):
|
||||||
|
manager = super(PolymorphicManager, cls).from_queryset(queryset_class, class_name=class_name)
|
||||||
|
manager.queryset_class = queryset_class # also set our version, Django uses _queryset_class
|
||||||
|
return manager
|
||||||
|
|
||||||
def __init__(self, queryset_class=None, *args, **kwrags):
|
def __init__(self, queryset_class=None, *args, **kwrags):
|
||||||
# Up till polymorphic 0.4, the queryset class could be specified as parameter to __init__.
|
# Up till polymorphic 0.4, the queryset class could be specified as parameter to __init__.
|
||||||
# However, this doesn't work for related managers which instantiate a new version of this class.
|
# However, this doesn't work for related managers which instantiate a new version of this class.
|
||||||
|
|
@ -44,18 +45,11 @@ class PolymorphicManager(models.Manager):
|
||||||
super(PolymorphicManager, self).__init__(*args, **kwrags)
|
super(PolymorphicManager, self).__init__(*args, **kwrags)
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
if django.VERSION >= (1, 7):
|
qs = self.queryset_class(self.model, using=self._db, hints=self._hints)
|
||||||
qs = self.queryset_class(self.model, using=self._db, hints=self._hints)
|
|
||||||
else:
|
|
||||||
qs = self.queryset_class(self.model, using=self._db)
|
|
||||||
if self.model._meta.proxy:
|
if self.model._meta.proxy:
|
||||||
qs = qs.instance_of(self.model)
|
qs = qs.instance_of(self.model)
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
# For Django 1.5
|
|
||||||
if django.VERSION < (1, 7):
|
|
||||||
get_query_set = get_queryset
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '%s (PolymorphicManager) using %s' % (self.__class__.__name__, self.queryset_class.__name__)
|
return '%s (PolymorphicManager) using %s' % (self.__class__.__name__, self.queryset_class.__name__)
|
||||||
|
|
||||||
|
|
@ -71,10 +65,3 @@ class PolymorphicManager(models.Manager):
|
||||||
|
|
||||||
def get_real_instances(self, base_result_objects=None):
|
def get_real_instances(self, base_result_objects=None):
|
||||||
return self.all().get_real_instances(base_result_objects=base_result_objects)
|
return self.all().get_real_instances(base_result_objects=base_result_objects)
|
||||||
|
|
||||||
if django.VERSION >= (1, 7):
|
|
||||||
@classmethod
|
|
||||||
def from_queryset(cls, queryset_class, class_name=None):
|
|
||||||
manager = super(PolymorphicManager, cls).from_queryset(queryset_class, class_name=class_name)
|
|
||||||
manager.queryset_class = queryset_class # also set our version, Django uses _queryset_class
|
|
||||||
return manager
|
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@ Seamless Polymorphic Inheritance for Django Models
|
||||||
"""
|
"""
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.utils import DEFAULT_DB_ALIAS
|
from django.db.utils import DEFAULT_DB_ALIAS
|
||||||
from django.contrib.contenttypes.models import ContentType
|
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
from .base import PolymorphicModelBase
|
from .base import PolymorphicModelBase
|
||||||
|
|
@ -85,11 +85,7 @@ class PolymorphicModel(six.with_metaclass(PolymorphicModelBase, models.Model)):
|
||||||
# so we use the following version, which uses the ContentType manager cache.
|
# so we use the following version, which uses the ContentType manager cache.
|
||||||
# Note that model_class() can return None for stale content types;
|
# Note that model_class() can return None for stale content types;
|
||||||
# when the content type record still exists but no longer refers to an existing model.
|
# when the content type record still exists but no longer refers to an existing model.
|
||||||
try:
|
model = ContentType.objects.db_manager(self._state.db).get_for_id(self.polymorphic_ctype_id).model_class()
|
||||||
model = ContentType.objects.db_manager(self._state.db).get_for_id(self.polymorphic_ctype_id).model_class()
|
|
||||||
except AttributeError:
|
|
||||||
# Django <1.6 workaround
|
|
||||||
return None
|
|
||||||
|
|
||||||
# Protect against bad imports (dumpdata without --natural) or other
|
# Protect against bad imports (dumpdata without --natural) or other
|
||||||
# issues missing with the ContentType models.
|
# issues missing with the ContentType models.
|
||||||
|
|
|
||||||
|
|
@ -8,21 +8,16 @@ import copy
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
import django
|
import django
|
||||||
from django.db.models.query import QuerySet, Q
|
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from django.db.models.query import Q, QuerySet
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
from .query_translate import translate_polymorphic_filter_definitions_in_kwargs, translate_polymorphic_filter_definitions_in_args
|
from .query_translate import translate_polymorphic_filter_definitions_in_kwargs, translate_polymorphic_filter_definitions_in_args
|
||||||
from .query_translate import translate_polymorphic_field_path, translate_polymorphic_Q_object
|
from .query_translate import translate_polymorphic_field_path, translate_polymorphic_Q_object
|
||||||
|
|
||||||
# chunk-size: maximum number of objects requested per db-request
|
# chunk-size: maximum number of objects requested per db-request
|
||||||
# by the PolymorphicModelIterable; we use the same chunk size as Django
|
# by the polymorphic queryset.iterator() implementation
|
||||||
try:
|
Polymorphic_QuerySet_objects_per_request = 100
|
||||||
from django.db.models.query import CHUNK_SIZE # this is 100 for Django 1.1/1.2
|
|
||||||
except ImportError:
|
|
||||||
# CHUNK_SIZE was removed in Django 1.6
|
|
||||||
CHUNK_SIZE = 100
|
|
||||||
Polymorphic_QuerySet_objects_per_request = CHUNK_SIZE
|
|
||||||
|
|
||||||
|
|
||||||
def _polymorphic_iterator(queryset, base_iter):
|
def _polymorphic_iterator(queryset, base_iter):
|
||||||
|
|
@ -97,14 +92,6 @@ def transmogrify(cls, obj):
|
||||||
###################################################################################
|
###################################################################################
|
||||||
# PolymorphicQuerySet
|
# PolymorphicQuerySet
|
||||||
|
|
||||||
def _query_annotations(query):
|
|
||||||
try:
|
|
||||||
return query.annotations
|
|
||||||
except AttributeError:
|
|
||||||
# Django < 1.8
|
|
||||||
return query.aggregates
|
|
||||||
|
|
||||||
|
|
||||||
class PolymorphicQuerySet(QuerySet):
|
class PolymorphicQuerySet(QuerySet):
|
||||||
"""
|
"""
|
||||||
QuerySet for PolymorphicModel
|
QuerySet for PolymorphicModel
|
||||||
|
|
@ -138,15 +125,13 @@ class PolymorphicQuerySet(QuerySet):
|
||||||
self.polymorphic_deferred_loading[1])
|
self.polymorphic_deferred_loading[1])
|
||||||
return new
|
return new
|
||||||
|
|
||||||
if django.VERSION >= (1, 7):
|
def as_manager(cls):
|
||||||
def as_manager(cls):
|
from .managers import PolymorphicManager
|
||||||
# Make sure the Django 1.7 way of creating managers works.
|
manager = PolymorphicManager.from_queryset(cls)()
|
||||||
from .managers import PolymorphicManager
|
manager._built_with_as_manager = True
|
||||||
manager = PolymorphicManager.from_queryset(cls)()
|
return manager
|
||||||
manager._built_with_as_manager = True
|
as_manager.queryset_only = True
|
||||||
return manager
|
as_manager = classmethod(as_manager)
|
||||||
as_manager.queryset_only = True
|
|
||||||
as_manager = classmethod(as_manager)
|
|
||||||
|
|
||||||
def non_polymorphic(self):
|
def non_polymorphic(self):
|
||||||
"""switch off polymorphic behaviour for this query.
|
"""switch off polymorphic behaviour for this query.
|
||||||
|
|
@ -244,47 +229,40 @@ class PolymorphicQuerySet(QuerySet):
|
||||||
Modifies kwargs if needed (these are Aggregate objects, we translate the lookup member variable)"""
|
Modifies kwargs if needed (these are Aggregate objects, we translate the lookup member variable)"""
|
||||||
___lookup_assert_msg = 'PolymorphicModel: annotate()/aggregate(): ___ model lookup supported for keyword arguments only'
|
___lookup_assert_msg = 'PolymorphicModel: annotate()/aggregate(): ___ model lookup supported for keyword arguments only'
|
||||||
|
|
||||||
if django.VERSION < (1, 8):
|
def patch_lookup(a):
|
||||||
def patch_lookup(a):
|
# The field on which the aggregate operates is
|
||||||
a.lookup = translate_polymorphic_field_path(self.model, a.lookup)
|
# stored inside a complex query expression.
|
||||||
|
if isinstance(a, Q):
|
||||||
|
translate_polymorphic_Q_object(self.model, a)
|
||||||
|
elif hasattr(a, 'get_source_expressions'):
|
||||||
|
for source_expression in a.get_source_expressions():
|
||||||
|
if source_expression is not None:
|
||||||
|
patch_lookup(source_expression)
|
||||||
|
else:
|
||||||
|
a.name = translate_polymorphic_field_path(self.model, a.name)
|
||||||
|
|
||||||
def test___lookup(a):
|
def test___lookup(a):
|
||||||
assert '___' not in a.lookup, ___lookup_assert_msg
|
""" *args might be complex expressions too in django 1.8 so
|
||||||
else:
|
the testing for a '___' is rather complex on this one """
|
||||||
def patch_lookup(a):
|
if isinstance(a, Q):
|
||||||
# With Django > 1.8, the field on which the aggregate operates is
|
def tree_node_test___lookup(my_model, node):
|
||||||
# stored inside a complex query expression.
|
" process all children of this Q node "
|
||||||
if isinstance(a, Q):
|
for i in range(len(node.children)):
|
||||||
translate_polymorphic_Q_object(self.model, a)
|
child = node.children[i]
|
||||||
elif hasattr(a, 'get_source_expressions'):
|
|
||||||
for source_expression in a.get_source_expressions():
|
|
||||||
if source_expression is not None:
|
|
||||||
patch_lookup(source_expression)
|
|
||||||
else:
|
|
||||||
a.name = translate_polymorphic_field_path(self.model, a.name)
|
|
||||||
|
|
||||||
def test___lookup(a):
|
if type(child) == tuple:
|
||||||
""" *args might be complex expressions too in django 1.8 so
|
# this Q object child is a tuple => a kwarg like Q( instance_of=ModelB )
|
||||||
the testing for a '___' is rather complex on this one """
|
assert '___' not in child[0], ___lookup_assert_msg
|
||||||
if isinstance(a, Q):
|
else:
|
||||||
def tree_node_test___lookup(my_model, node):
|
# this Q object child is another Q object, recursively process this as well
|
||||||
" process all children of this Q node "
|
tree_node_test___lookup(my_model, child)
|
||||||
for i in range(len(node.children)):
|
|
||||||
child = node.children[i]
|
|
||||||
|
|
||||||
if type(child) == tuple:
|
tree_node_test___lookup(self.model, a)
|
||||||
# this Q object child is a tuple => a kwarg like Q( instance_of=ModelB )
|
elif hasattr(a, 'get_source_expressions'):
|
||||||
assert '___' not in child[0], ___lookup_assert_msg
|
for source_expression in a.get_source_expressions():
|
||||||
else:
|
test___lookup(source_expression)
|
||||||
# this Q object child is another Q object, recursively process this as well
|
else:
|
||||||
tree_node_test___lookup(my_model, child)
|
assert '___' not in a.name, ___lookup_assert_msg
|
||||||
|
|
||||||
tree_node_test___lookup(self.model, a)
|
|
||||||
elif hasattr(a, 'get_source_expressions'):
|
|
||||||
for source_expression in a.get_source_expressions():
|
|
||||||
test___lookup(source_expression)
|
|
||||||
else:
|
|
||||||
assert '___' not in a.name, ___lookup_assert_msg
|
|
||||||
|
|
||||||
for a in args:
|
for a in args:
|
||||||
test___lookup(a)
|
test___lookup(a)
|
||||||
|
|
@ -438,8 +416,8 @@ class PolymorphicQuerySet(QuerySet):
|
||||||
if real_class != real_concrete_class:
|
if real_class != real_concrete_class:
|
||||||
real_object = transmogrify(real_class, real_object)
|
real_object = transmogrify(real_class, real_object)
|
||||||
|
|
||||||
if _query_annotations(self.query):
|
if self.query.annotations:
|
||||||
for anno_field_name in six.iterkeys(_query_annotations(self.query)):
|
for anno_field_name in six.iterkeys(self.query.annotations):
|
||||||
attr = getattr(base_result_objects_by_id[o_pk], anno_field_name)
|
attr = getattr(base_result_objects_by_id[o_pk], anno_field_name)
|
||||||
setattr(real_object, anno_field_name, attr)
|
setattr(real_object, anno_field_name, attr)
|
||||||
|
|
||||||
|
|
@ -454,8 +432,8 @@ class PolymorphicQuerySet(QuerySet):
|
||||||
resultlist = [results[ordered_id] for ordered_id in ordered_id_list if ordered_id in results]
|
resultlist = [results[ordered_id] for ordered_id in ordered_id_list if ordered_id in results]
|
||||||
|
|
||||||
# set polymorphic_annotate_names in all objects (currently just used for debugging/printing)
|
# set polymorphic_annotate_names in all objects (currently just used for debugging/printing)
|
||||||
if _query_annotations(self.query):
|
if self.query.annotations:
|
||||||
annotate_names = list(six.iterkeys(_query_annotations(self.query))) # get annotate field list
|
annotate_names = list(six.iterkeys(self.query.annotations)) # get annotate field list
|
||||||
for real_object in resultlist:
|
for real_object in resultlist:
|
||||||
real_object.polymorphic_annotate_names = annotate_names
|
real_object.polymorphic_annotate_names = annotate_names
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,26 +7,12 @@ from __future__ import absolute_import
|
||||||
import copy
|
import copy
|
||||||
import django
|
import django
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
from django.db import models
|
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db.models import Q, FieldDoesNotExist
|
from django.db import models
|
||||||
|
from django.db.models.fields.related import ForeignObjectRel, RelatedField
|
||||||
from django.db.utils import DEFAULT_DB_ALIAS
|
from django.db.utils import DEFAULT_DB_ALIAS
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
from django.db.models.fields.related import RelatedField
|
|
||||||
if django.VERSION < (1, 6):
|
|
||||||
# There was no common base class in Django 1.5, mention all variants here.
|
|
||||||
from django.db.models.fields.related import RelatedObject, ManyToOneRel, ManyToManyRel
|
|
||||||
REL_FIELD_CLASSES = (RelatedField, RelatedObject, ManyToOneRel, ManyToManyRel) # Leaving GenericRel out.
|
|
||||||
elif django.VERSION < (1, 8):
|
|
||||||
# As of Django 1.6 there is a ForeignObjectRel.
|
|
||||||
from django.db.models.fields.related import ForeignObjectRel, RelatedObject
|
|
||||||
REL_FIELD_CLASSES = (RelatedField, ForeignObjectRel, RelatedObject)
|
|
||||||
else:
|
|
||||||
# As of Django 1.8 the base class serves everything. RelatedObject is gone.
|
|
||||||
from django.db.models.fields.related import ForeignObjectRel
|
|
||||||
REL_FIELD_CLASSES = (RelatedField, ForeignObjectRel)
|
|
||||||
|
|
||||||
|
|
||||||
###################################################################################
|
###################################################################################
|
||||||
# PolymorphicQuerySet support functions
|
# PolymorphicQuerySet support functions
|
||||||
|
|
@ -102,7 +88,7 @@ def translate_polymorphic_filter_definitions_in_args(queryset_model, args, using
|
||||||
"""
|
"""
|
||||||
if django.VERSION >= (1, 10):
|
if django.VERSION >= (1, 10):
|
||||||
q_objects = [copy.deepcopy(q) for q in args]
|
q_objects = [copy.deepcopy(q) for q in args]
|
||||||
elif django.VERSION >= (1, 6):
|
elif django.VERSION >= (1, 8):
|
||||||
q_objects = [q.clone() for q in args]
|
q_objects = [q.clone() for q in args]
|
||||||
else:
|
else:
|
||||||
q_objects = args # NOTE: edits existing objects in place.
|
q_objects = args # NOTE: edits existing objects in place.
|
||||||
|
|
@ -175,17 +161,14 @@ def translate_polymorphic_field_path(queryset_model, field_path):
|
||||||
# Test whether it's actually a regular relation__ _fieldname (the field starting with an _)
|
# Test whether it's actually a regular relation__ _fieldname (the field starting with an _)
|
||||||
# so no tripple ClassName___field was intended.
|
# so no tripple ClassName___field was intended.
|
||||||
try:
|
try:
|
||||||
if django.VERSION >= (1, 8):
|
# This also retreives M2M relations now (including reverse foreign key relations)
|
||||||
# This also retreives M2M relations now (including reverse foreign key relations)
|
field = queryset_model._meta.get_field(classname)
|
||||||
field = queryset_model._meta.get_field(classname)
|
|
||||||
else:
|
|
||||||
field = queryset_model._meta.get_field_by_name(classname)[0]
|
|
||||||
|
|
||||||
if isinstance(field, REL_FIELD_CLASSES):
|
if isinstance(field, (RelatedField, ForeignObjectRel)):
|
||||||
# Can also test whether the field exists in the related object to avoid ambiguity between
|
# 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.
|
# 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.
|
return field_path # No exception raised, field does exist.
|
||||||
except FieldDoesNotExist:
|
except models.FieldDoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# function to collect all sub-models, this should be optimized (cached)
|
# function to collect all sub-models, this should be optimized (cached)
|
||||||
|
|
@ -261,7 +244,7 @@ def _create_model_filter_Q(modellist, not_instance_of=False, using=DEFAULT_DB_AL
|
||||||
assert False, 'PolymorphicModel: instance_of expects a list of (polymorphic) models or a single (polymorphic) model'
|
assert False, 'PolymorphicModel: instance_of expects a list of (polymorphic) models or a single (polymorphic) model'
|
||||||
|
|
||||||
def q_class_with_subclasses(model):
|
def q_class_with_subclasses(model):
|
||||||
q = Q(polymorphic_ctype=ContentType.objects.db_manager(using).get_for_model(model, for_concrete_model=False))
|
q = models.Q(polymorphic_ctype=ContentType.objects.db_manager(using).get_for_model(model, for_concrete_model=False))
|
||||||
for subclass in model.__subclasses__():
|
for subclass in model.__subclasses__():
|
||||||
q = q | q_class_with_subclasses(subclass)
|
q = q | q_class_with_subclasses(subclass)
|
||||||
return q
|
return q
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import django
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
from django.utils.six import python_2_unicode_compatible
|
||||||
|
|
||||||
try:
|
|
||||||
from django.utils.six import python_2_unicode_compatible
|
|
||||||
except ImportError:
|
|
||||||
from django.utils.encoding import python_2_unicode_compatible # Django 1.5
|
|
||||||
|
|
||||||
RE_DEFERRED = re.compile('_Deferred_.*')
|
RE_DEFERRED = re.compile('_Deferred_.*')
|
||||||
|
|
||||||
|
|
@ -157,11 +154,6 @@ class ShowFieldBase(object):
|
||||||
|
|
||||||
return '<' + out + '>'
|
return '<' + out + '>'
|
||||||
|
|
||||||
if django.VERSION < (1, 8):
|
|
||||||
def get_deferred_fields(self):
|
|
||||||
from django.db.models.query_utils import DeferredAttribute
|
|
||||||
return set(attr for attr, value in self.__class__.__dict__.items() if isinstance(value, DeferredAttribute))
|
|
||||||
|
|
||||||
|
|
||||||
class ShowFieldType(ShowFieldBase):
|
class ShowFieldType(ShowFieldBase):
|
||||||
""" model mixin that shows the object's class and it's field types """
|
""" model mixin that shows the object's class and it's field types """
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,16 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import django
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
from django.contrib.contenttypes.models import ContentType
|
|
||||||
|
|
||||||
from polymorphic.managers import PolymorphicManager
|
from polymorphic.managers import PolymorphicManager
|
||||||
from polymorphic.models import PolymorphicModel
|
from polymorphic.models import PolymorphicModel
|
||||||
from polymorphic.query import PolymorphicQuerySet
|
from polymorphic.query import PolymorphicQuerySet
|
||||||
from polymorphic.showfields import ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent
|
from polymorphic.showfields import ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent
|
||||||
|
|
||||||
try:
|
|
||||||
from django.db.models import UUIDField
|
|
||||||
except ImportError:
|
|
||||||
# django<1.8
|
|
||||||
from polymorphic.tools_for_tests import UUIDField
|
|
||||||
|
|
||||||
|
|
||||||
class PlainA(models.Model):
|
class PlainA(models.Model):
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
|
|
@ -167,9 +161,6 @@ class MyManager(PolymorphicManager):
|
||||||
def my_queryset_foo(self):
|
def my_queryset_foo(self):
|
||||||
return self.all().my_queryset_foo()
|
return self.all().my_queryset_foo()
|
||||||
|
|
||||||
# Django <= 1.5 compatibility
|
|
||||||
get_query_set = get_queryset
|
|
||||||
|
|
||||||
|
|
||||||
class ModelWithMyManager(ShowFieldTypeAndContent, Model2A):
|
class ModelWithMyManager(ShowFieldTypeAndContent, Model2A):
|
||||||
objects = MyManager()
|
objects = MyManager()
|
||||||
|
|
@ -188,10 +179,9 @@ class ModelWithMyManagerDefault(ShowFieldTypeAndContent, Model2A):
|
||||||
field4 = models.CharField(max_length=10)
|
field4 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
if django.VERSION >= (1, 7):
|
class ModelWithMyManager2(ShowFieldTypeAndContent, Model2A):
|
||||||
class ModelWithMyManager2(ShowFieldTypeAndContent, Model2A):
|
objects = MyManagerQuerySet.as_manager()
|
||||||
objects = MyManagerQuerySet.as_manager()
|
field4 = models.CharField(max_length=10)
|
||||||
field4 = models.CharField(max_length=10)
|
|
||||||
|
|
||||||
|
|
||||||
class MROBase1(ShowFieldType, PolymorphicModel):
|
class MROBase1(ShowFieldType, PolymorphicModel):
|
||||||
|
|
@ -236,9 +226,6 @@ class PlainMyManager(models.Manager):
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return PlainMyManagerQuerySet(self.model, using=self._db)
|
return PlainMyManagerQuerySet(self.model, using=self._db)
|
||||||
|
|
||||||
# Django <= 1.5 compatibility
|
|
||||||
get_query_set = get_queryset
|
|
||||||
|
|
||||||
|
|
||||||
class PlainParentModelWithManager(models.Model):
|
class PlainParentModelWithManager(models.Model):
|
||||||
pass
|
pass
|
||||||
|
|
@ -319,7 +306,7 @@ class Bottom(Middle):
|
||||||
|
|
||||||
|
|
||||||
class UUIDProject(ShowFieldTypeAndContent, PolymorphicModel):
|
class UUIDProject(ShowFieldTypeAndContent, PolymorphicModel):
|
||||||
uuid_primary_key = UUIDField(primary_key=True, default=uuid.uuid1)
|
uuid_primary_key = models.UUIDField(primary_key=True, default=uuid.uuid1)
|
||||||
topic = models.CharField(max_length=30)
|
topic = models.CharField(max_length=30)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -332,7 +319,7 @@ class UUIDResearchProject(UUIDProject):
|
||||||
|
|
||||||
|
|
||||||
class UUIDPlainA(models.Model):
|
class UUIDPlainA(models.Model):
|
||||||
uuid_primary_key = UUIDField(primary_key=True, default=uuid.uuid1)
|
uuid_primary_key = models.UUIDField(primary_key=True, default=uuid.uuid1)
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,15 @@
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
import django
|
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
|
||||||
from django.test import TestCase
|
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
from polymorphic.tests import * # all models
|
from polymorphic.tests import * # all models
|
||||||
|
|
||||||
try:
|
|
||||||
from unittest import skipIf
|
|
||||||
except ImportError:
|
|
||||||
# python<2.7
|
|
||||||
from django.utils.unittest import skipIf
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MultipleDatabasesTests(TestCase):
|
class MultipleDatabasesTests(TestCase):
|
||||||
multi_db = True
|
multi_db = True
|
||||||
|
|
||||||
@skipIf(django.VERSION < (1, 5,), "This test needs Django >=1.5")
|
|
||||||
def test_save_to_non_default_database(self):
|
def test_save_to_non_default_database(self):
|
||||||
Model2A.objects.db_manager('secondary').create(field1='A1')
|
Model2A.objects.db_manager('secondary').create(field1='A1')
|
||||||
Model2C(field1='C1', field2='C2', field3='C3').save(using='secondary')
|
Model2C(field1='C1', field2='C2', field3='C3').save(using='secondary')
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,11 @@
|
||||||
from __future__ import print_function
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
import django
|
import django
|
||||||
|
from django.db.models import Case, Count, Q, When
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.db.models import Q, Count
|
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from polymorphic.tests import * # all models
|
|
||||||
|
|
||||||
from polymorphic.contrib.guardian import get_polymorphic_base_content_type
|
from polymorphic.contrib.guardian import get_polymorphic_base_content_type
|
||||||
|
from polymorphic.tests import * # all models
|
||||||
try:
|
|
||||||
from unittest import skipIf
|
|
||||||
except ImportError:
|
|
||||||
# python<2.7
|
|
||||||
from django.utils.unittest import skipIf
|
|
||||||
|
|
||||||
if django.VERSION >= (1, 8):
|
|
||||||
from django.db.models import Case, When
|
|
||||||
|
|
||||||
|
|
||||||
class PolymorphicTests(TestCase):
|
class PolymorphicTests(TestCase):
|
||||||
|
|
@ -188,11 +177,6 @@ class PolymorphicTests(TestCase):
|
||||||
'<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField), '
|
'<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField), '
|
||||||
'deferred[field2,field3,field4,model2a_ptr_id,model2b_ptr_id]>')
|
'deferred[field2,field3,field4,model2a_ptr_id,model2b_ptr_id]>')
|
||||||
|
|
||||||
# A bug in Django 1.4 prevents using defer across reverse relations
|
|
||||||
# <https://code.djangoproject.com/ticket/14694>. Since polymorphic
|
|
||||||
# uses reverse relations to traverse down model inheritance, deferring
|
|
||||||
# fields in child models will not work in Django 1.4.
|
|
||||||
@skipIf(django.VERSION < (1, 5), "Django 1.4 does not support defer on related fields")
|
|
||||||
def test_defer_related_fields(self):
|
def test_defer_related_fields(self):
|
||||||
self.create_model2abcd()
|
self.create_model2abcd()
|
||||||
|
|
||||||
|
|
@ -424,7 +408,6 @@ class PolymorphicTests(TestCase):
|
||||||
self.assertEqual(repr(objects[0]), '<Model2B: id 2, field1 (CharField), field2 (CharField)>')
|
self.assertEqual(repr(objects[0]), '<Model2B: id 2, field1 (CharField), field2 (CharField)>')
|
||||||
self.assertEqual(repr(objects[1]), '<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>')
|
self.assertEqual(repr(objects[1]), '<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>')
|
||||||
|
|
||||||
@skipIf(django.VERSION < (1, 6), "Django 1.4 and 1.5 don't support q.clone()")
|
|
||||||
def test_query_filter_exclude_is_immutable(self):
|
def test_query_filter_exclude_is_immutable(self):
|
||||||
# given
|
# given
|
||||||
q_to_reuse = Q(Model2B___field2='something')
|
q_to_reuse = Q(Model2B___field2='something')
|
||||||
|
|
@ -564,7 +547,6 @@ class PolymorphicTests(TestCase):
|
||||||
self.assertIs(type(ModelWithMyManagerDefault._default_manager), MyManager)
|
self.assertIs(type(ModelWithMyManagerDefault._default_manager), MyManager)
|
||||||
self.assertIs(type(ModelWithMyManagerDefault.base_objects), models.Manager)
|
self.assertIs(type(ModelWithMyManagerDefault.base_objects), models.Manager)
|
||||||
|
|
||||||
@skipIf(django.VERSION < (1, 7), "This test needs Django 1.7+")
|
|
||||||
def test_user_defined_queryset_as_manager(self):
|
def test_user_defined_queryset_as_manager(self):
|
||||||
self.create_model2abcd()
|
self.create_model2abcd()
|
||||||
ModelWithMyManager2.objects.create(field1='D1a', field4='D4a')
|
ModelWithMyManager2.objects.create(field1='D1a', field4='D4a')
|
||||||
|
|
@ -751,7 +733,6 @@ class PolymorphicTests(TestCase):
|
||||||
lambda: Model2A.objects.aggregate(Count('Model2B___field2'))
|
lambda: Model2A.objects.aggregate(Count('Model2B___field2'))
|
||||||
)
|
)
|
||||||
|
|
||||||
@skipIf(django.VERSION < (1, 8,), "This test needs Django >=1.8")
|
|
||||||
def test_polymorphic__complex_aggregate(self):
|
def test_polymorphic__complex_aggregate(self):
|
||||||
""" test (complex expression on) aggregate (should work for annotate either) """
|
""" test (complex expression on) aggregate (should work for annotate either) """
|
||||||
|
|
||||||
|
|
@ -777,7 +758,6 @@ class PolymorphicTests(TestCase):
|
||||||
with self.assertRaisesMessage(AssertionError, 'PolymorphicModel: annotate()/aggregate(): ___ model lookup supported for keyword arguments only'):
|
with self.assertRaisesMessage(AssertionError, 'PolymorphicModel: annotate()/aggregate(): ___ model lookup supported for keyword arguments only'):
|
||||||
Model2A.objects.aggregate(ComplexAgg('Model2B___field2'))
|
Model2A.objects.aggregate(ComplexAgg('Model2B___field2'))
|
||||||
|
|
||||||
@skipIf(django.VERSION < (1, 8,), "This test needs Django >=1.8")
|
|
||||||
def test_polymorphic__expressions(self):
|
def test_polymorphic__expressions(self):
|
||||||
|
|
||||||
from django.db.models.functions import Concat
|
from django.db.models.functions import Concat
|
||||||
|
|
|
||||||
|
|
@ -1,144 +0,0 @@
|
||||||
# Compatibility module for Django < 1.8
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
from django import forms
|
|
||||||
from django.db import models
|
|
||||||
from django.utils.encoding import smart_text
|
|
||||||
from django.utils import six
|
|
||||||
|
|
||||||
|
|
||||||
class UUIDVersionError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class UUIDField(six.with_metaclass(models.SubfieldBase, models.CharField)):
|
|
||||||
"""Encode and stores a Python uuid.UUID in a manner that is appropriate
|
|
||||||
for the given datatabase that we are using.
|
|
||||||
|
|
||||||
For sqlite3 or MySQL we save it as a 36-character string value
|
|
||||||
For PostgreSQL we save it as a uuid field
|
|
||||||
|
|
||||||
This class supports type 1, 2, 4, and 5 UUID's.
|
|
||||||
"""
|
|
||||||
|
|
||||||
_CREATE_COLUMN_TYPES = {
|
|
||||||
'postgresql_psycopg2': 'uuid',
|
|
||||||
'postgresql': 'uuid'
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, verbose_name=None, name=None, auto=True, version=1, node=None, clock_seq=None, namespace=None, **kwargs):
|
|
||||||
"""Contruct a UUIDField.
|
|
||||||
|
|
||||||
@param verbose_name: Optional verbose name to use in place of what
|
|
||||||
Django would assign.
|
|
||||||
@param name: Override Django's name assignment
|
|
||||||
@param auto: If True, create a UUID value if one is not specified.
|
|
||||||
@param version: By default we create a version 1 UUID.
|
|
||||||
@param node: Used for version 1 UUID's. If not supplied, then the uuid.getnode() function is called to obtain it. This can be slow.
|
|
||||||
@param clock_seq: Used for version 1 UUID's. If not supplied a random 14-bit sequence number is chosen
|
|
||||||
@param namespace: Required for version 3 and version 5 UUID's.
|
|
||||||
@param name: Required for version4 and version 5 UUID's.
|
|
||||||
|
|
||||||
See Also:
|
|
||||||
- Python Library Reference, section 18.16 for more information.
|
|
||||||
- RFC 4122, "A Universally Unique IDentifier (UUID) URN Namespace"
|
|
||||||
|
|
||||||
If you want to use one of these as a primary key for a Django
|
|
||||||
model, do this::
|
|
||||||
id = UUIDField(primary_key=True)
|
|
||||||
This will currently I{not} work with Jython because PostgreSQL support
|
|
||||||
in Jython is not working for uuid column types.
|
|
||||||
"""
|
|
||||||
self.max_length = 36
|
|
||||||
kwargs['max_length'] = self.max_length
|
|
||||||
if auto:
|
|
||||||
kwargs['blank'] = True
|
|
||||||
kwargs.setdefault('editable', False)
|
|
||||||
|
|
||||||
self.auto = auto
|
|
||||||
self.version = version
|
|
||||||
if version == 1:
|
|
||||||
self.node, self.clock_seq = node, clock_seq
|
|
||||||
elif version == 3 or version == 5:
|
|
||||||
self.namespace, self.name = namespace, name
|
|
||||||
|
|
||||||
super(UUIDField, self).__init__(verbose_name=verbose_name,
|
|
||||||
name=name, **kwargs)
|
|
||||||
|
|
||||||
def create_uuid(self):
|
|
||||||
if not self.version or self.version == 4:
|
|
||||||
return uuid.uuid4()
|
|
||||||
elif self.version == 1:
|
|
||||||
return uuid.uuid1(self.node, self.clock_seq)
|
|
||||||
elif self.version == 2:
|
|
||||||
raise UUIDVersionError("UUID version 2 is not supported.")
|
|
||||||
elif self.version == 3:
|
|
||||||
return uuid.uuid3(self.namespace, self.name)
|
|
||||||
elif self.version == 5:
|
|
||||||
return uuid.uuid5(self.namespace, self.name)
|
|
||||||
else:
|
|
||||||
raise UUIDVersionError("UUID version %s is not valid." % self.version)
|
|
||||||
|
|
||||||
def db_type(self, connection):
|
|
||||||
from django.conf import settings
|
|
||||||
full_database_type = settings.DATABASES['default']['ENGINE']
|
|
||||||
database_type = full_database_type.split('.')[-1]
|
|
||||||
return UUIDField._CREATE_COLUMN_TYPES.get(database_type, "char(%s)" % self.max_length)
|
|
||||||
|
|
||||||
def to_python(self, value):
|
|
||||||
"""Return a uuid.UUID instance from the value returned by the database."""
|
|
||||||
#
|
|
||||||
# This is the proper way... But this doesn't work correctly when
|
|
||||||
# working with an inherited model
|
|
||||||
#
|
|
||||||
if not value:
|
|
||||||
return None
|
|
||||||
if isinstance(value, uuid.UUID):
|
|
||||||
return value
|
|
||||||
# attempt to parse a UUID
|
|
||||||
return uuid.UUID(smart_text(value))
|
|
||||||
|
|
||||||
#
|
|
||||||
# If I do the following (returning a String instead of a UUID
|
|
||||||
# instance), everything works.
|
|
||||||
#
|
|
||||||
|
|
||||||
# if not value:
|
|
||||||
# return None
|
|
||||||
# if isinstance(value, uuid.UUID):
|
|
||||||
# return smart_text(value)
|
|
||||||
# else:
|
|
||||||
# return value
|
|
||||||
|
|
||||||
def pre_save(self, model_instance, add):
|
|
||||||
if self.auto and add:
|
|
||||||
value = self.create_uuid()
|
|
||||||
setattr(model_instance, self.attname, value)
|
|
||||||
else:
|
|
||||||
value = super(UUIDField, self).pre_save(model_instance, add)
|
|
||||||
if self.auto and not value:
|
|
||||||
value = self.create_uuid()
|
|
||||||
setattr(model_instance, self.attname, value)
|
|
||||||
return value
|
|
||||||
|
|
||||||
def get_db_prep_value(self, value, connection, prepared):
|
|
||||||
"""Casts uuid.UUID values into the format expected by the back end for use in queries"""
|
|
||||||
if isinstance(value, uuid.UUID):
|
|
||||||
return smart_text(value)
|
|
||||||
return value
|
|
||||||
|
|
||||||
def value_to_string(self, obj):
|
|
||||||
val = self._get_val_from_obj(obj)
|
|
||||||
if val is None:
|
|
||||||
data = ''
|
|
||||||
else:
|
|
||||||
data = smart_text(val)
|
|
||||||
return data
|
|
||||||
|
|
||||||
def formfield(self, **kwargs):
|
|
||||||
defaults = {
|
|
||||||
'form_class': forms.CharField,
|
|
||||||
'max_length': self.max_length
|
|
||||||
}
|
|
||||||
defaults.update(kwargs)
|
|
||||||
return super(UUIDField, self).formfield(**defaults)
|
|
||||||
73
runtests.py
73
runtests.py
|
|
@ -1,12 +1,10 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
import django
|
from os.path import abspath, dirname
|
||||||
|
|
||||||
|
import django
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.management import execute_from_command_line
|
from django.core.management import execute_from_command_line
|
||||||
from django.conf import settings, global_settings as default_settings
|
|
||||||
from os.path import dirname, realpath, abspath
|
|
||||||
|
|
||||||
|
|
||||||
# Give feedback on used versions
|
# Give feedback on used versions
|
||||||
|
|
@ -17,42 +15,6 @@ sys.stderr.write('Using Django version {0} from {1}\n'.format(
|
||||||
)
|
)
|
||||||
|
|
||||||
if not settings.configured:
|
if not settings.configured:
|
||||||
if django.VERSION >= (1, 8):
|
|
||||||
template_settings = dict(
|
|
||||||
TEMPLATES = [
|
|
||||||
{
|
|
||||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
|
||||||
'DIRS': (),
|
|
||||||
'OPTIONS': {
|
|
||||||
'loaders': (
|
|
||||||
'django.template.loaders.filesystem.Loader',
|
|
||||||
'django.template.loaders.app_directories.Loader',
|
|
||||||
),
|
|
||||||
'context_processors': (
|
|
||||||
'django.template.context_processors.debug',
|
|
||||||
'django.template.context_processors.i18n',
|
|
||||||
'django.template.context_processors.media',
|
|
||||||
'django.template.context_processors.request',
|
|
||||||
'django.template.context_processors.static',
|
|
||||||
'django.contrib.messages.context_processors.messages',
|
|
||||||
'django.contrib.auth.context_processors.auth',
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
template_settings = dict(
|
|
||||||
TEMPLATE_LOADERS = (
|
|
||||||
'django.template.loaders.app_directories.Loader',
|
|
||||||
'django.template.loaders.filesystem.Loader',
|
|
||||||
),
|
|
||||||
TEMPLATE_CONTEXT_PROCESSORS = list(default_settings.TEMPLATE_CONTEXT_PROCESSORS) + [
|
|
||||||
'django.contrib.messages.context_processors.messages',
|
|
||||||
'django.core.context_processors.request',
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
settings.configure(
|
settings.configure(
|
||||||
DEBUG=False,
|
DEBUG=False,
|
||||||
DATABASES={
|
DATABASES={
|
||||||
|
|
@ -65,8 +27,8 @@ if not settings.configured:
|
||||||
'NAME': ':memory:'
|
'NAME': ':memory:'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
TEST_RUNNER = 'django.test.runner.DiscoverRunner' if django.VERSION >= (1, 7) else 'django.test.simple.DjangoTestSuiteRunner',
|
TEST_RUNNER="django.test.runner.DiscoverRunner",
|
||||||
INSTALLED_APPS = (
|
INSTALLED_APPS=(
|
||||||
'django.contrib.auth',
|
'django.contrib.auth',
|
||||||
'django.contrib.contenttypes',
|
'django.contrib.contenttypes',
|
||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
|
|
@ -74,11 +36,31 @@ if not settings.configured:
|
||||||
'django.contrib.admin',
|
'django.contrib.admin',
|
||||||
'polymorphic',
|
'polymorphic',
|
||||||
),
|
),
|
||||||
MIDDLEWARE_CLASSES = (),
|
MIDDLEWARE_CLASSES=(),
|
||||||
SITE_ID = 3,
|
SITE_ID=3,
|
||||||
**template_settings
|
TEMPLATES=[{
|
||||||
|
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||||
|
"DIRS": (),
|
||||||
|
"OPTIONS": {
|
||||||
|
"loaders": (
|
||||||
|
"django.template.loaders.filesystem.Loader",
|
||||||
|
"django.template.loaders.app_directories.Loader",
|
||||||
|
),
|
||||||
|
"context_processors": (
|
||||||
|
"django.template.context_processors.debug",
|
||||||
|
"django.template.context_processors.i18n",
|
||||||
|
"django.template.context_processors.media",
|
||||||
|
"django.template.context_processors.request",
|
||||||
|
"django.template.context_processors.static",
|
||||||
|
"django.contrib.messages.context_processors.messages",
|
||||||
|
"django.contrib.auth.context_processors.auth",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_TEST_APPS = [
|
DEFAULT_TEST_APPS = [
|
||||||
'polymorphic',
|
'polymorphic',
|
||||||
]
|
]
|
||||||
|
|
@ -90,5 +72,6 @@ def runtests():
|
||||||
argv = sys.argv[:1] + ['test', '--traceback'] + other_args + test_apps
|
argv = sys.argv[:1] + ['test', '--traceback'] + other_args + test_apps
|
||||||
execute_from_command_line(argv)
|
execute_from_command_line(argv)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
runtests()
|
runtests()
|
||||||
|
|
|
||||||
17
setup.py
17
setup.py
|
|
@ -1,10 +1,9 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
from setuptools import setup, find_packages
|
|
||||||
from os import path
|
|
||||||
import codecs
|
import codecs
|
||||||
import os
|
|
||||||
import re
|
import re
|
||||||
import sys
|
from os import path
|
||||||
|
|
||||||
|
from setuptools import find_packages, setup
|
||||||
|
|
||||||
|
|
||||||
def read(*parts):
|
def read(*parts):
|
||||||
|
|
@ -47,18 +46,14 @@ setup(
|
||||||
'License :: OSI Approved :: BSD License',
|
'License :: OSI Approved :: BSD License',
|
||||||
'Operating System :: OS Independent',
|
'Operating System :: OS Independent',
|
||||||
'Programming Language :: Python',
|
'Programming Language :: Python',
|
||||||
'Programming Language :: Python :: 2.6',
|
|
||||||
'Programming Language :: Python :: 2.7',
|
'Programming Language :: Python :: 2.7',
|
||||||
'Programming Language :: Python :: 3.2',
|
|
||||||
'Programming Language :: Python :: 3.3',
|
|
||||||
'Programming Language :: Python :: 3.4',
|
'Programming Language :: Python :: 3.4',
|
||||||
'Programming Language :: Python :: 3.5',
|
'Programming Language :: Python :: 3.5',
|
||||||
|
'Programming Language :: Python :: 3.6',
|
||||||
'Framework :: Django',
|
'Framework :: Django',
|
||||||
'Framework :: Django :: 1.4',
|
|
||||||
'Framework :: Django :: 1.5',
|
|
||||||
'Framework :: Django :: 1.6',
|
|
||||||
'Framework :: Django :: 1.7',
|
|
||||||
'Framework :: Django :: 1.8',
|
'Framework :: Django :: 1.8',
|
||||||
|
'Framework :: Django :: 1.10',
|
||||||
|
'Framework :: Django :: 1.11',
|
||||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue