Merge remote-tracking branch 'upstream/master' into allow_extra_manager
commit
b17aa58ad9
|
|
@ -202,7 +202,7 @@ Nicely Displaying Polymorphic Querysets
|
||||||
In order to get the output as seen in all examples here, you need to use the
|
In order to get the output as seen in all examples here, you need to use the
|
||||||
:class:`~polymorphic.showfields.ShowFieldType` class mixin::
|
:class:`~polymorphic.showfields.ShowFieldType` class mixin::
|
||||||
|
|
||||||
from polymorphic import PolymorphicModel, ShowFieldType
|
from polymorphic.showfields import PolymorphicModel, ShowFieldType
|
||||||
|
|
||||||
class ModelA(ShowFieldType, PolymorphicModel):
|
class ModelA(ShowFieldType, PolymorphicModel):
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,42 @@
|
||||||
Changelog
|
Changelog
|
||||||
==========
|
==========
|
||||||
|
|
||||||
|
Version 0.8.1 (2015-12-29)
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
* Fixed support for reverse relations for ``relname___field`` when the field starts with an ``_`` character.
|
||||||
|
Otherwise, the query will be interpreted as subclass lookup (``ClassName___field``).
|
||||||
|
|
||||||
|
|
||||||
|
Version 0.8 (2015-12-28)
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
* Added Django 1.9 compatibility.
|
||||||
|
* Renamed ``polymorphic.manager`` => ``polymorphic.managers`` for consistentcy.
|
||||||
|
* **BACKWARDS INCOMPATIBILITY:** The import paths have changed to support Django 1.9.
|
||||||
|
Instead of ``from polymorphic import X``,
|
||||||
|
you'll have to import from the proper package. For example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
polymorphic.models import PolymorphicModel
|
||||||
|
polymorphic.managers import PolymorphicManager, PolymorphicQuerySet
|
||||||
|
polymorphic.showfields import ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent
|
||||||
|
|
||||||
|
* **BACKWARDS INCOMPATIBILITY:** Removed ``__version__.py`` in favor of a standard ``__version__`` in ``polymorphic/__init__.py``.
|
||||||
|
* **BACKWARDS INCOMPATIBILITY:** Removed automatic proxying of method calls to the queryset class.
|
||||||
|
Use the standard Django methods instead:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# In model code:
|
||||||
|
objects = PolymorphicQuerySet.as_manager()
|
||||||
|
|
||||||
|
# For manager code:
|
||||||
|
MyCustomManager = PolymorphicManager.from_queryset(MyCustomQuerySet)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Version 0.7.2 (2015-10-01)
|
Version 0.7.2 (2015-10-01)
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
|
|
|
||||||
29
docs/conf.py
29
docs/conf.py
|
|
@ -11,7 +11,8 @@
|
||||||
# All configuration values have a default; values that are commented out
|
# All configuration values have a default; values that are commented out
|
||||||
# serve to show the default.
|
# serve to show the default.
|
||||||
|
|
||||||
import sys, os
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
# If extensions (or modules to document with autodoc) are in another directory,
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
# add these directories to sys.path here. If the directory is relative to the
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
|
|
@ -54,9 +55,9 @@ copyright = u'2013, Bert Constantin, Chris Glass, Diederik van der Boor'
|
||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '0.7.2'
|
version = '0.8.1'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '0.7.2'
|
release = '0.8.1'
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
|
@ -176,21 +177,21 @@ htmlhelp_basename = 'django-polymorphicdoc'
|
||||||
# -- Options for LaTeX output --------------------------------------------------
|
# -- Options for LaTeX output --------------------------------------------------
|
||||||
|
|
||||||
latex_elements = {
|
latex_elements = {
|
||||||
# The paper size ('letterpaper' or 'a4paper').
|
# The paper size ('letterpaper' or 'a4paper').
|
||||||
#'papersize': 'letterpaper',
|
#'papersize': 'letterpaper',
|
||||||
|
|
||||||
# The font size ('10pt', '11pt' or '12pt').
|
# The font size ('10pt', '11pt' or '12pt').
|
||||||
#'pointsize': '10pt',
|
#'pointsize': '10pt',
|
||||||
|
|
||||||
# Additional stuff for the LaTeX preamble.
|
# Additional stuff for the LaTeX preamble.
|
||||||
#'preamble': '',
|
#'preamble': '',
|
||||||
}
|
}
|
||||||
|
|
||||||
# Grouping the document tree into LaTeX files. List of tuples
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||||
latex_documents = [
|
latex_documents = [
|
||||||
('index', 'django-polymorphic.tex', u'django-polymorphic Documentation',
|
('index', 'django-polymorphic.tex', u'django-polymorphic Documentation',
|
||||||
u'Bert Constantin, Chris Glass, Diederik van der Boor', 'manual'),
|
u'Bert Constantin, Chris Glass, Diederik van der Boor', 'manual'),
|
||||||
]
|
]
|
||||||
|
|
||||||
# The name of an image file (relative to this directory) to place at the top of
|
# The name of an image file (relative to this directory) to place at the top of
|
||||||
|
|
@ -233,9 +234,9 @@ man_pages = [
|
||||||
# (source start file, target name, title, author,
|
# (source start file, target name, title, author,
|
||||||
# dir menu entry, description, category)
|
# dir menu entry, description, category)
|
||||||
texinfo_documents = [
|
texinfo_documents = [
|
||||||
('index', 'django-polymorphic', u'django-polymorphic Documentation',
|
('index', 'django-polymorphic', u'django-polymorphic Documentation',
|
||||||
u'Bert Constantin, Chris Glass, Diederik van der Boor', 'django-polymorphic', 'One line description of project.',
|
u'Bert Constantin, Chris Glass, Diederik van der Boor', 'django-polymorphic', 'One line description of project.',
|
||||||
'Miscellaneous'),
|
'Miscellaneous'),
|
||||||
]
|
]
|
||||||
|
|
||||||
# Documents to append as an appendix to all manuals.
|
# Documents to append as an appendix to all manuals.
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ INSTALLED_APPS = (
|
||||||
'pexp', # this Django app is for testing and experimentation; not needed otherwise
|
'pexp', # this Django app is for testing and experimentation; not needed otherwise
|
||||||
)
|
)
|
||||||
|
|
||||||
if django.VERSION >= (1,7):
|
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
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ class ProjectChildAdmin(PolymorphicChildModelAdmin):
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ProjectAdmin(PolymorphicParentModelAdmin):
|
class ProjectAdmin(PolymorphicParentModelAdmin):
|
||||||
base_model = Project
|
base_model = Project
|
||||||
list_filter = (PolymorphicChildModelFilter,)
|
list_filter = (PolymorphicChildModelFilter,)
|
||||||
|
|
@ -26,10 +27,10 @@ class ProjectAdmin(PolymorphicParentModelAdmin):
|
||||||
admin.site.register(Project, ProjectAdmin)
|
admin.site.register(Project, ProjectAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ModelAChildAdmin(PolymorphicChildModelAdmin):
|
class ModelAChildAdmin(PolymorphicChildModelAdmin):
|
||||||
base_model = ModelA
|
base_model = ModelA
|
||||||
|
|
||||||
|
|
||||||
class ModelAAdmin(PolymorphicParentModelAdmin):
|
class ModelAAdmin(PolymorphicParentModelAdmin):
|
||||||
base_model = ModelA
|
base_model = ModelA
|
||||||
list_filter = (PolymorphicChildModelFilter,)
|
list_filter = (PolymorphicChildModelFilter,)
|
||||||
|
|
@ -45,6 +46,7 @@ admin.site.register(ModelA, ModelAAdmin)
|
||||||
class Model2AChildAdmin(PolymorphicChildModelAdmin):
|
class Model2AChildAdmin(PolymorphicChildModelAdmin):
|
||||||
base_model = Model2A
|
base_model = Model2A
|
||||||
|
|
||||||
|
|
||||||
class Model2AAdmin(PolymorphicParentModelAdmin):
|
class Model2AAdmin(PolymorphicParentModelAdmin):
|
||||||
base_model = Model2A
|
base_model = Model2A
|
||||||
list_filter = (PolymorphicChildModelFilter,)
|
list_filter = (PolymorphicChildModelFilter,)
|
||||||
|
|
@ -60,6 +62,7 @@ admin.site.register(Model2A, Model2AAdmin)
|
||||||
class UUIDModelAChildAdmin(PolymorphicChildModelAdmin):
|
class UUIDModelAChildAdmin(PolymorphicChildModelAdmin):
|
||||||
base_model = UUIDModelA
|
base_model = UUIDModelA
|
||||||
|
|
||||||
|
|
||||||
class UUIDModelAAdmin(PolymorphicParentModelAdmin):
|
class UUIDModelAAdmin(PolymorphicParentModelAdmin):
|
||||||
base_model = UUIDModelA
|
base_model = UUIDModelA
|
||||||
list_filter = (PolymorphicChildModelFilter,)
|
list_filter = (PolymorphicChildModelFilter,)
|
||||||
|
|
@ -75,6 +78,7 @@ admin.site.register(UUIDModelA, UUIDModelAAdmin)
|
||||||
class ProxyChildAdmin(PolymorphicChildModelAdmin):
|
class ProxyChildAdmin(PolymorphicChildModelAdmin):
|
||||||
base_model = ProxyBase
|
base_model = ProxyBase
|
||||||
|
|
||||||
|
|
||||||
class ProxyAdmin(PolymorphicParentModelAdmin):
|
class ProxyAdmin(PolymorphicParentModelAdmin):
|
||||||
base_model = ProxyBase
|
base_model = ProxyBase
|
||||||
list_filter = (PolymorphicChildModelFilter,)
|
list_filter = (PolymorphicChildModelFilter,)
|
||||||
|
|
|
||||||
|
|
@ -4,80 +4,97 @@ 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.
|
||||||
"""
|
"""
|
||||||
import uuid
|
import uuid
|
||||||
|
import django
|
||||||
|
|
||||||
from django.core.management.base import NoArgsCommand
|
from django.core.management.base import NoArgsCommand
|
||||||
from django.db.models import connection
|
from django.db import connection
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
import time,sys
|
import time
|
||||||
|
import sys
|
||||||
|
|
||||||
from pexp.models import *
|
from pexp.models import *
|
||||||
|
|
||||||
|
|
||||||
def reset_queries():
|
def reset_queries():
|
||||||
connection.queries=[]
|
if django.VERSION < (1, 9):
|
||||||
|
connection.queries = []
|
||||||
|
else:
|
||||||
|
connection.queries_log.clear()
|
||||||
|
|
||||||
|
|
||||||
def show_queries():
|
def show_queries():
|
||||||
print; print 'QUERIES:',len(connection.queries); pprint(connection.queries); print; connection.queries=[]
|
print
|
||||||
|
print 'QUERIES:', len(connection.queries)
|
||||||
|
pprint(connection.queries)
|
||||||
|
print
|
||||||
|
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()
|
reset_queries()
|
||||||
for i in xrange(iterations):
|
for i in xrange(iterations):
|
||||||
t1 = time.time()
|
t1 = time.time()
|
||||||
x = func(*arg)
|
x = func(*arg)
|
||||||
t2 = time.time()
|
t2 = time.time()
|
||||||
results.append((t2-t1)*1000.0)
|
results.append((t2 - t1) * 1000.0)
|
||||||
res_sum=0
|
res_sum = 0
|
||||||
for r in results: res_sum +=r
|
for r in results:
|
||||||
|
res_sum += r
|
||||||
median = res_sum / len(results)
|
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
|
||||||
|
|
||||||
|
|
||||||
class Command(NoArgsCommand):
|
class Command(NoArgsCommand):
|
||||||
help = ""
|
help = ""
|
||||||
|
|
||||||
def handle_noargs(self, **options):
|
def handle_noargs(self, **options):
|
||||||
if False:
|
if False:
|
||||||
ModelA.objects.all().delete()
|
ModelA.objects.all().delete()
|
||||||
a=ModelA.objects.create(field1='A1')
|
a = ModelA.objects.create(field1='A1')
|
||||||
b=ModelB.objects.create(field1='B1', field2='B2')
|
b = ModelB.objects.create(field1='B1', field2='B2')
|
||||||
c=ModelC.objects.create(field1='C1', field2='C2', field3='C3')
|
c = ModelC.objects.create(field1='C1', field2='C2', field3='C3')
|
||||||
reset_queries()
|
reset_queries()
|
||||||
print ModelC.base_objects.all();
|
print ModelC.base_objects.all()
|
||||||
show_queries()
|
show_queries()
|
||||||
|
|
||||||
if False:
|
if False:
|
||||||
ModelA.objects.all().delete()
|
ModelA.objects.all().delete()
|
||||||
for i in xrange(1000):
|
for i in xrange(1000):
|
||||||
a=ModelA.objects.create(field1=str(i%100))
|
a = ModelA.objects.create(field1=str(i % 100))
|
||||||
b=ModelB.objects.create(field1=str(i%100), field2=str(i%200))
|
b = ModelB.objects.create(field1=str(i % 100), field2=str(i % 200))
|
||||||
c=ModelC.objects.create(field1=str(i%100), field2=str(i%200), field3=str(i%300))
|
c = ModelC.objects.create(field1=str(i % 100), field2=str(i % 200), field3=str(i % 300))
|
||||||
if i%100==0: print i
|
if i % 100 == 0:
|
||||||
|
print i
|
||||||
|
|
||||||
f=print_timing(poly_sql_query,iterations=1000)
|
f = print_timing(poly_sql_query, iterations=1000)
|
||||||
f()
|
f()
|
||||||
|
|
||||||
f=print_timing(poly_sql_query2,iterations=1000)
|
f = print_timing(poly_sql_query2, iterations=1000)
|
||||||
f()
|
f()
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
nModelA.objects.all().delete()
|
nModelA.objects.all().delete()
|
||||||
a=nModelA.objects.create(field1='A1')
|
a = nModelA.objects.create(field1='A1')
|
||||||
b=nModelB.objects.create(field1='B1', field2='B2')
|
b = nModelB.objects.create(field1='B1', field2='B2')
|
||||||
c=nModelC.objects.create(field1='C1', field2='C2', field3='C3')
|
c = nModelC.objects.create(field1='C1', field2='C2', field3='C3')
|
||||||
qs=ModelA.objects.raw("SELECT * from pexp_modela")
|
qs = ModelA.objects.raw("SELECT * from pexp_modela")
|
||||||
for o in list(qs): print o
|
for o in list(qs):
|
||||||
|
print o
|
||||||
|
|
||||||
from django.db import connection, transaction
|
from django.db import connection, transaction
|
||||||
from random import Random
|
from random import Random
|
||||||
rnd=Random()
|
rnd = Random()
|
||||||
|
|
||||||
|
|
||||||
def poly_sql_query():
|
def poly_sql_query():
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
|
|
@ -90,10 +107,11 @@ def poly_sql_query():
|
||||||
ON pexp_modelb.modela_ptr_id = pexp_modelc.modelb_ptr_id
|
ON pexp_modelb.modela_ptr_id = pexp_modelc.modelb_ptr_id
|
||||||
WHERE pexp_modela.field1=%i
|
WHERE pexp_modela.field1=%i
|
||||||
ORDER BY pexp_modela.id
|
ORDER BY pexp_modela.id
|
||||||
""" % rnd.randint(0,100) )
|
""" % rnd.randint(0, 100) )
|
||||||
#row=cursor.fetchone()
|
# row=cursor.fetchone()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def poly_sql_query2():
|
def poly_sql_query2():
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
|
|
@ -101,6 +119,6 @@ def poly_sql_query2():
|
||||||
FROM pexp_modela
|
FROM pexp_modela
|
||||||
WHERE pexp_modela.field1=%i
|
WHERE pexp_modela.field1=%i
|
||||||
ORDER BY pexp_modela.id
|
ORDER BY pexp_modela.id
|
||||||
""" % rnd.randint(0,100) )
|
""" % rnd.randint(0, 100) )
|
||||||
#row=cursor.fetchone()
|
# row=cursor.fetchone()
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -4,32 +4,38 @@ This module is a scratchpad for general development, testing & debugging.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.core.management.base import NoArgsCommand
|
from django.core.management.base import NoArgsCommand
|
||||||
from django.db.models import connection
|
from django.db import connection
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
|
||||||
from pexp.models import *
|
from pexp.models import *
|
||||||
|
|
||||||
|
|
||||||
def reset_queries():
|
def reset_queries():
|
||||||
connection.queries=[]
|
connection.queries = []
|
||||||
|
|
||||||
|
|
||||||
def show_queries():
|
def show_queries():
|
||||||
print; print 'QUERIES:',len(connection.queries); pprint(connection.queries); print; connection.queries=[]
|
print
|
||||||
|
print 'QUERIES:', len(connection.queries)
|
||||||
|
pprint(connection.queries)
|
||||||
|
print
|
||||||
|
connection.queries = []
|
||||||
|
|
||||||
|
|
||||||
class Command(NoArgsCommand):
|
class Command(NoArgsCommand):
|
||||||
help = ""
|
help = ""
|
||||||
|
|
||||||
def handle_noargs(self, **options):
|
def handle_noargs(self, **options):
|
||||||
Project.objects.all().delete()
|
Project.objects.all().delete()
|
||||||
a=Project.objects.create(topic="John's gathering")
|
a = Project.objects.create(topic="John's gathering")
|
||||||
b=ArtProject.objects.create(topic="Sculpting with Tim", artist="T. Turner")
|
b = ArtProject.objects.create(topic="Sculpting with Tim", artist="T. Turner")
|
||||||
c=ResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter")
|
c = ResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter")
|
||||||
print Project.objects.all()
|
print Project.objects.all()
|
||||||
print
|
print
|
||||||
|
|
||||||
ModelA.objects.all().delete()
|
ModelA.objects.all().delete()
|
||||||
a=ModelA.objects.create(field1='A1')
|
a = ModelA.objects.create(field1='A1')
|
||||||
b=ModelB.objects.create(field1='B1', field2='B2')
|
b = ModelB.objects.create(field1='B1', field2='B2')
|
||||||
c=ModelC.objects.create(field1='C1', field2='C2', field3='C3')
|
c = ModelC.objects.create(field1='C1', field2='C2', field3='C3')
|
||||||
print ModelA.objects.all()
|
print ModelA.objects.all()
|
||||||
print
|
print
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,101 +3,120 @@
|
||||||
This module is a scratchpad for general development, testing & debugging
|
This module is a scratchpad for general development, testing & debugging
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import django
|
||||||
from django.core.management.base import NoArgsCommand
|
from django.core.management.base import NoArgsCommand
|
||||||
from django.db.models import connection
|
from django.db import connection
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
import sys
|
import sys
|
||||||
from pexp.models import *
|
from pexp.models import *
|
||||||
|
|
||||||
num_objects=1000
|
num_objects = 1000
|
||||||
|
|
||||||
|
|
||||||
def reset_queries():
|
def reset_queries():
|
||||||
connection.queries=[]
|
if django.VERSION < (1, 9):
|
||||||
|
connection.queries = []
|
||||||
|
else:
|
||||||
|
connection.queries_log.clear()
|
||||||
|
|
||||||
|
|
||||||
def show_queries():
|
def show_queries():
|
||||||
print; print 'QUERIES:',len(connection.queries); pprint(connection.queries); print; reset_queries()
|
print
|
||||||
|
print 'QUERIES:', len(connection.queries)
|
||||||
|
pprint(connection.queries)
|
||||||
|
print
|
||||||
|
reset_queries()
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
###################################################################################
|
###################################################################################
|
||||||
### benchmark wrappers
|
# benchmark wrappers
|
||||||
|
|
||||||
|
|
||||||
def print_timing(func, message='', iterations=1):
|
def print_timing(func, message='', iterations=1):
|
||||||
def wrapper(*arg):
|
def wrapper(*arg):
|
||||||
results=[]
|
results = []
|
||||||
reset_queries()
|
reset_queries()
|
||||||
for i in xrange(iterations):
|
for i in xrange(iterations):
|
||||||
t1 = time.time()
|
t1 = time.time()
|
||||||
x = func(*arg)
|
x = func(*arg)
|
||||||
t2 = time.time()
|
t2 = time.time()
|
||||||
results.append((t2-t1)*1000.0)
|
results.append((t2 - t1) * 1000.0)
|
||||||
res_sum=0
|
res_sum = 0
|
||||||
for r in results: res_sum +=r
|
for r in results:
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
def run_vanilla_any_poly(func, iterations=1):
|
def run_vanilla_any_poly(func, iterations=1):
|
||||||
f=print_timing(func,' ', iterations)
|
f = print_timing(func, ' ', iterations)
|
||||||
f(nModelC)
|
f(nModelC)
|
||||||
f=print_timing(func,'poly ', iterations)
|
f = print_timing(func, 'poly ', iterations)
|
||||||
f(ModelC)
|
f(ModelC)
|
||||||
|
|
||||||
|
|
||||||
###################################################################################
|
###################################################################################
|
||||||
### benchmarks
|
# benchmarks
|
||||||
|
|
||||||
def bench_create(model):
|
def bench_create(model):
|
||||||
for i in xrange(num_objects):
|
for i in xrange(num_objects):
|
||||||
model.objects.create(field1='abc'+str(i), field2='abcd'+str(i), field3='abcde'+str(i))
|
model.objects.create(field1='abc' + str(i), field2='abcd' + str(i), field3='abcde' + str(i))
|
||||||
#print 'count:',model.objects.count()
|
# print 'count:',model.objects.count()
|
||||||
|
|
||||||
|
|
||||||
def bench_load1(model):
|
def bench_load1(model):
|
||||||
for o in model.objects.all():
|
for o in model.objects.all():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def bench_load1_short(model):
|
def bench_load1_short(model):
|
||||||
for i in xrange(num_objects/100):
|
for i in xrange(num_objects / 100):
|
||||||
for o in model.objects.all()[:100]:
|
for o in model.objects.all()[:100]:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def bench_load2(model):
|
def bench_load2(model):
|
||||||
for o in model.objects.all():
|
for o in model.objects.all():
|
||||||
f1=o.field1
|
f1 = o.field1
|
||||||
f2=o.field2
|
f2 = o.field2
|
||||||
f3=o.field3
|
f3 = o.field3
|
||||||
|
|
||||||
|
|
||||||
def bench_load2_short(model):
|
def bench_load2_short(model):
|
||||||
for i in xrange(num_objects/100):
|
for i in xrange(num_objects / 100):
|
||||||
for o in model.objects.all()[:100]:
|
for o in model.objects.all()[:100]:
|
||||||
f1=o.field1
|
f1 = o.field1
|
||||||
f2=o.field2
|
f2 = o.field2
|
||||||
f3=o.field3
|
f3 = o.field3
|
||||||
|
|
||||||
|
|
||||||
def bench_delete(model):
|
def bench_delete(model):
|
||||||
model.objects.all().delete()
|
model.objects.all().delete()
|
||||||
|
|
||||||
###################################################################################
|
###################################################################################
|
||||||
### Command
|
# Command
|
||||||
|
|
||||||
|
|
||||||
class Command(NoArgsCommand):
|
class Command(NoArgsCommand):
|
||||||
help = ""
|
help = ""
|
||||||
|
|
||||||
def handle_noargs(self, **options):
|
def handle_noargs(self, **options):
|
||||||
func_list = [
|
func_list = [
|
||||||
( bench_delete, 1 ),
|
(bench_delete, 1),
|
||||||
( bench_create, 1 ),
|
(bench_create, 1),
|
||||||
( bench_load1, 5 ),
|
(bench_load1, 5),
|
||||||
( bench_load1_short, 5 ),
|
(bench_load1_short, 5),
|
||||||
( bench_load2, 5 ),
|
(bench_load2, 5),
|
||||||
( bench_load2_short, 5 )
|
(bench_load2_short, 5)
|
||||||
]
|
]
|
||||||
for f,iterations in func_list:
|
for f, iterations in func_list:
|
||||||
run_vanilla_any_poly(f,iterations=iterations)
|
run_vanilla_any_poly(f, iterations=iterations)
|
||||||
|
|
||||||
print
|
print
|
||||||
|
|
|
||||||
|
|
@ -4,27 +4,31 @@ This module is a scratchpad for general development, testing & debugging
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.core.management.base import NoArgsCommand
|
from django.core.management.base import NoArgsCommand
|
||||||
from django.db.models import connection
|
from django.db import connection
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
|
||||||
from pexp.models import *
|
from pexp.models import *
|
||||||
|
|
||||||
|
|
||||||
def reset_queries():
|
def reset_queries():
|
||||||
connection.queries=[]
|
connection.queries = []
|
||||||
|
|
||||||
|
|
||||||
def show_queries():
|
def show_queries():
|
||||||
print; print 'QUERIES:',len(connection.queries); pprint(connection.queries); print; connection.queries=[]
|
print
|
||||||
|
print 'QUERIES:', len(connection.queries)
|
||||||
|
pprint(connection.queries)
|
||||||
|
print
|
||||||
|
connection.queries = []
|
||||||
|
|
||||||
|
|
||||||
class Command(NoArgsCommand):
|
class Command(NoArgsCommand):
|
||||||
help = ""
|
help = ""
|
||||||
|
|
||||||
def handle_noargs(self, **options):
|
def handle_noargs(self, **options):
|
||||||
Project.objects.all().delete()
|
Project.objects.all().delete()
|
||||||
o=Project.objects.create(topic="John's gathering")
|
o = Project.objects.create(topic="John's gathering")
|
||||||
o=ArtProject.objects.create(topic="Sculpting with Tim", artist="T. Turner")
|
o = ArtProject.objects.create(topic="Sculpting with Tim", artist="T. Turner")
|
||||||
o=ResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter")
|
o = ResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter")
|
||||||
print Project.objects.all()
|
print Project.objects.all()
|
||||||
print
|
print
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,48 +6,74 @@ from django.db import models
|
||||||
from polymorphic.models import PolymorphicModel
|
from polymorphic.models import PolymorphicModel
|
||||||
from polymorphic.showfields import ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent
|
from polymorphic.showfields import ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent
|
||||||
|
|
||||||
|
|
||||||
class Project(ShowFieldContent, PolymorphicModel):
|
class Project(ShowFieldContent, PolymorphicModel):
|
||||||
topic = models.CharField(max_length=30)
|
topic = models.CharField(max_length=30)
|
||||||
|
|
||||||
|
|
||||||
class ArtProject(Project):
|
class ArtProject(Project):
|
||||||
artist = models.CharField(max_length=30)
|
artist = models.CharField(max_length=30)
|
||||||
|
|
||||||
|
|
||||||
class ResearchProject(Project):
|
class ResearchProject(Project):
|
||||||
supervisor = models.CharField(max_length=30)
|
supervisor = models.CharField(max_length=30)
|
||||||
|
|
||||||
|
|
||||||
class ModelA(ShowFieldTypeAndContent, PolymorphicModel):
|
class ModelA(ShowFieldTypeAndContent, PolymorphicModel):
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class ModelB(ModelA):
|
class ModelB(ModelA):
|
||||||
field2 = models.CharField(max_length=10)
|
field2 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class ModelC(ModelB):
|
class ModelC(ModelB):
|
||||||
field3 = models.CharField(max_length=10)
|
field3 = models.CharField(max_length=10)
|
||||||
field4 = models.ManyToManyField(ModelB, related_name='related_c')
|
field4 = models.ManyToManyField(ModelB, related_name='related_c')
|
||||||
|
|
||||||
|
|
||||||
class nModelA(models.Model):
|
class nModelA(models.Model):
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class nModelB(nModelA):
|
class nModelB(nModelA):
|
||||||
field2 = models.CharField(max_length=10)
|
field2 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class nModelC(nModelB):
|
class nModelC(nModelB):
|
||||||
field3 = models.CharField(max_length=10)
|
field3 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class Model2A(PolymorphicModel):
|
class Model2A(PolymorphicModel):
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class Model2B(Model2A):
|
class Model2B(Model2A):
|
||||||
field2 = models.CharField(max_length=10)
|
field2 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class Model2C(Model2B):
|
class Model2C(Model2B):
|
||||||
field3 = models.CharField(max_length=10)
|
field3 = models.CharField(max_length=10)
|
||||||
|
|
||||||
if django.VERSION < (1,8):
|
if django.VERSION < (1, 8):
|
||||||
from polymorphic.tools_for_tests import UUIDField
|
from polymorphic.tools_for_tests import UUIDField
|
||||||
else:
|
else:
|
||||||
from django.db.models import UUIDField
|
from django.db.models import UUIDField
|
||||||
|
|
||||||
|
|
||||||
class UUIDModelA(ShowFieldTypeAndContent, PolymorphicModel):
|
class UUIDModelA(ShowFieldTypeAndContent, PolymorphicModel):
|
||||||
uuid_primary_key = UUIDField(primary_key = True)
|
uuid_primary_key = UUIDField(primary_key=True)
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class UUIDModelB(UUIDModelA):
|
class UUIDModelB(UUIDModelA):
|
||||||
field2 = models.CharField(max_length=10)
|
field2 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class UUIDModelC(UUIDModelB):
|
class UUIDModelC(UUIDModelB):
|
||||||
field3 = models.CharField(max_length=10)
|
field3 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class ProxyBase(PolymorphicModel):
|
class ProxyBase(PolymorphicModel):
|
||||||
title = models.CharField(max_length=200)
|
title = models.CharField(max_length=200)
|
||||||
|
|
||||||
|
|
@ -57,14 +83,18 @@ class ProxyBase(PolymorphicModel):
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('title',)
|
ordering = ('title',)
|
||||||
|
|
||||||
|
|
||||||
class ProxyA(ProxyBase):
|
class ProxyA(ProxyBase):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
proxy = True
|
proxy = True
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u"<ProxyA: {0}>".format(self.title)
|
return u"<ProxyA: {0}>".format(self.title)
|
||||||
|
|
||||||
|
|
||||||
class ProxyB(ProxyBase):
|
class ProxyB(ProxyBase):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
proxy = True
|
proxy = True
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,12 @@ 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.
|
||||||
"""
|
"""
|
||||||
from __future__ import absolute_import
|
# See PEP 440 (https://www.python.org/dev/peps/pep-0440/)
|
||||||
import django
|
__version__ = "0.8.1"
|
||||||
from .showfields import ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent
|
|
||||||
from .showfields import ShowFields, ShowFieldTypes, ShowFieldsAndTypes # import old names for compatibility
|
|
||||||
|
|
||||||
|
|
||||||
# Monkey-patch Django < 1.5 to allow ContentTypes for proxy models.
|
# Monkey-patch Django < 1.5 to allow ContentTypes for proxy models.
|
||||||
|
import django
|
||||||
if django.VERSION[:2] < (1, 5):
|
if django.VERSION[:2] < (1, 5):
|
||||||
from django.contrib.contenttypes.models import ContentTypeManager
|
from django.contrib.contenttypes.models import ContentTypeManager
|
||||||
from django.utils.encoding import smart_text
|
from django.utils.encoding import smart_text
|
||||||
|
|
@ -29,9 +28,9 @@ if django.VERSION[:2] < (1, 5):
|
||||||
ct = self._get_from_cache(opts)
|
ct = self._get_from_cache(opts)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
ct, created = self.get_or_create(
|
ct, created = self.get_or_create(
|
||||||
app_label = opts.app_label,
|
app_label=opts.app_label,
|
||||||
model = opts.object_name.lower(),
|
model=opts.object_name.lower(),
|
||||||
defaults = {'name': smart_text(opts.verbose_name_raw)},
|
defaults={'name': smart_text(opts.verbose_name_raw)},
|
||||||
)
|
)
|
||||||
self._add_to_cache(self.db, ct)
|
self._add_to_cache(self.db, ct)
|
||||||
|
|
||||||
|
|
@ -39,4 +38,3 @@ if django.VERSION[:2] < (1, 5):
|
||||||
|
|
||||||
ContentTypeManager.get_for_model__original = ContentTypeManager.get_for_model
|
ContentTypeManager.get_for_model__original = ContentTypeManager.get_for_model
|
||||||
ContentTypeManager.get_for_model = get_for_model
|
ContentTypeManager.get_for_model = get_for_model
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
See PEP 440 (https://www.python.org/dev/peps/pep-0440/)
|
|
||||||
"""
|
|
||||||
__version__ = "0.7.2"
|
|
||||||
|
|
@ -42,6 +42,7 @@ 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."
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ChildAdminNotRegistered(RuntimeError):
|
class ChildAdminNotRegistered(RuntimeError):
|
||||||
"The admin site for the model is not registered."
|
"The admin site for the model is not registered."
|
||||||
pass
|
pass
|
||||||
|
|
@ -122,13 +123,11 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
||||||
#: If your primary key consists of string values, update this regular expression.
|
#: If your primary key consists of string values, update this regular expression.
|
||||||
pk_regex = '(\d+|__fk__)'
|
pk_regex = '(\d+|__fk__)'
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, model, admin_site, *args, **kwargs):
|
def __init__(self, model, admin_site, *args, **kwargs):
|
||||||
super(PolymorphicParentModelAdmin, self).__init__(model, admin_site, *args, **kwargs)
|
super(PolymorphicParentModelAdmin, self).__init__(model, admin_site, *args, **kwargs)
|
||||||
self._child_admin_site = self.admin_site.__class__(name=self.admin_site.name)
|
self._child_admin_site = self.admin_site.__class__(name=self.admin_site.name)
|
||||||
self._is_setup = False
|
self._is_setup = False
|
||||||
|
|
||||||
|
|
||||||
def _lazy_setup(self):
|
def _lazy_setup(self):
|
||||||
if self._is_setup:
|
if self._is_setup:
|
||||||
return
|
return
|
||||||
|
|
@ -150,7 +149,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
||||||
self._child_admin_site._registry = complete_registry
|
self._child_admin_site._registry = complete_registry
|
||||||
self._is_setup = True
|
self._is_setup = True
|
||||||
|
|
||||||
|
|
||||||
def register_child(self, model, model_admin):
|
def register_child(self, model, model_admin):
|
||||||
"""
|
"""
|
||||||
Register a model with admin to display.
|
Register a model with admin to display.
|
||||||
|
|
@ -167,7 +165,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
self._child_admin_site.register(model, model_admin)
|
self._child_admin_site.register(model, model_admin)
|
||||||
|
|
||||||
|
|
||||||
def get_child_models(self):
|
def get_child_models(self):
|
||||||
"""
|
"""
|
||||||
Return the derived model classes which this admin should handle.
|
Return the derived model classes which this admin should handle.
|
||||||
|
|
@ -181,7 +178,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
return self.child_models
|
return self.child_models
|
||||||
|
|
||||||
|
|
||||||
def get_child_type_choices(self, request, action):
|
def get_child_type_choices(self, request, action):
|
||||||
"""
|
"""
|
||||||
Return a list of polymorphic types for which the user has the permission to perform the given action.
|
Return a list of polymorphic types for which the user has the permission to perform the given action.
|
||||||
|
|
@ -197,7 +193,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
||||||
choices.append((ct.id, model._meta.verbose_name))
|
choices.append((ct.id, model._meta.verbose_name))
|
||||||
return choices
|
return choices
|
||||||
|
|
||||||
|
|
||||||
def _get_real_admin(self, object_id):
|
def _get_real_admin(self, object_id):
|
||||||
try:
|
try:
|
||||||
obj = self.model.objects.non_polymorphic() \
|
obj = self.model.objects.non_polymorphic() \
|
||||||
|
|
@ -206,7 +201,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
||||||
raise Http404
|
raise Http404
|
||||||
return self._get_real_admin_by_ct(obj['polymorphic_ctype'])
|
return self._get_real_admin_by_ct(obj['polymorphic_ctype'])
|
||||||
|
|
||||||
|
|
||||||
def _get_real_admin_by_ct(self, ct_id):
|
def _get_real_admin_by_ct(self, ct_id):
|
||||||
try:
|
try:
|
||||||
ct = ContentType.objects.get_for_id(ct_id)
|
ct = ContentType.objects.get_for_id(ct_id)
|
||||||
|
|
@ -219,7 +213,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
return self._get_real_admin_by_model(model_class)
|
return self._get_real_admin_by_model(model_class)
|
||||||
|
|
||||||
|
|
||||||
def _get_real_admin_by_model(self, model_class):
|
def _get_real_admin_by_model(self, model_class):
|
||||||
# In case of a ?ct_id=### parameter, the view is already checked for permissions.
|
# In case of a ?ct_id=### parameter, the view is already checked for permissions.
|
||||||
# Hence, make sure this is a derived object, or risk exposing other admin interfaces.
|
# Hence, make sure this is a derived object, or risk exposing other admin interfaces.
|
||||||
|
|
@ -233,7 +226,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise ChildAdminNotRegistered("No child admin site was registered for a '{0}' model.".format(model_class))
|
raise ChildAdminNotRegistered("No child admin site was registered for a '{0}' model.".format(model_class))
|
||||||
|
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
# optimize the list display.
|
# optimize the list display.
|
||||||
qs = super(PolymorphicParentModelAdmin, self).get_queryset(request)
|
qs = super(PolymorphicParentModelAdmin, self).get_queryset(request)
|
||||||
|
|
@ -241,7 +233,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
||||||
qs = qs.non_polymorphic()
|
qs = qs.non_polymorphic()
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
|
|
||||||
# For Django 1.5:
|
# For Django 1.5:
|
||||||
def queryset(self, request):
|
def queryset(self, request):
|
||||||
qs = super(PolymorphicParentModelAdmin, self).queryset(request)
|
qs = super(PolymorphicParentModelAdmin, self).queryset(request)
|
||||||
|
|
@ -249,7 +240,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
||||||
qs = qs.non_polymorphic()
|
qs = qs.non_polymorphic()
|
||||||
return qs
|
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))
|
||||||
|
|
@ -266,13 +256,11 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
||||||
)
|
)
|
||||||
return real_admin.add_view(request, form_url, extra_context)
|
return real_admin.add_view(request, form_url, extra_context)
|
||||||
|
|
||||||
|
|
||||||
def change_view(self, request, object_id, *args, **kwargs):
|
def change_view(self, request, object_id, *args, **kwargs):
|
||||||
"""Redirect the change view to the real admin."""
|
"""Redirect the change view to the real admin."""
|
||||||
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)
|
||||||
|
|
||||||
|
|
||||||
def delete_view(self, request, object_id, extra_context=None):
|
def delete_view(self, request, object_id, extra_context=None):
|
||||||
"""Redirect the delete view to the real admin."""
|
"""Redirect the delete view to the real admin."""
|
||||||
real_admin = self._get_real_admin(object_id)
|
real_admin = self._get_real_admin(object_id)
|
||||||
|
|
@ -331,7 +319,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
return urls + custom_urls + dummy_urls
|
return urls + custom_urls + dummy_urls
|
||||||
|
|
||||||
|
|
||||||
def subclass_view(self, request, path):
|
def subclass_view(self, request, path):
|
||||||
"""
|
"""
|
||||||
Forward any request to a custom view of the real admin.
|
Forward any request to a custom view of the real admin.
|
||||||
|
|
@ -350,7 +337,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
ct_id = self.model.objects.values_list('polymorphic_ctype_id', flat=True).get(pk=object_id)
|
ct_id = self.model.objects.values_list('polymorphic_ctype_id', flat=True).get(pk=object_id)
|
||||||
|
|
||||||
|
|
||||||
real_admin = self._get_real_admin_by_ct(ct_id)
|
real_admin = self._get_real_admin_by_ct(ct_id)
|
||||||
resolver = RegexURLResolver('^', real_admin.urls)
|
resolver = RegexURLResolver('^', real_admin.urls)
|
||||||
resolvermatch = resolver.resolve(path) # May raise Resolver404
|
resolvermatch = resolver.resolve(path) # May raise Resolver404
|
||||||
|
|
@ -359,7 +345,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
return resolvermatch.func(request, *resolvermatch.args, **resolvermatch.kwargs)
|
return resolvermatch.func(request, *resolvermatch.args, **resolvermatch.kwargs)
|
||||||
|
|
||||||
|
|
||||||
def add_type_view(self, request, form_url=''):
|
def add_type_view(self, request, form_url=''):
|
||||||
"""
|
"""
|
||||||
Display a choice form to select which page type to add.
|
Display a choice form to select which page type to add.
|
||||||
|
|
@ -402,7 +387,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
||||||
}
|
}
|
||||||
return self.render_add_type_form(request, context, form_url)
|
return self.render_add_type_form(request, context, form_url)
|
||||||
|
|
||||||
|
|
||||||
def render_add_type_form(self, request, context, form_url=''):
|
def render_add_type_form(self, request, context, form_url=''):
|
||||||
"""
|
"""
|
||||||
Render the page type choice form.
|
Render the page type choice form.
|
||||||
|
|
@ -426,7 +410,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
||||||
"admin/add_type_form.html"
|
"admin/add_type_form.html"
|
||||||
], context, context_instance=context_instance)
|
], context, context_instance=context_instance)
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def change_list_template(self):
|
def change_list_template(self):
|
||||||
opts = self.model._meta
|
opts = self.model._meta
|
||||||
|
|
@ -446,7 +429,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PolymorphicChildModelAdmin(admin.ModelAdmin):
|
class PolymorphicChildModelAdmin(admin.ModelAdmin):
|
||||||
"""
|
"""
|
||||||
The *optional* base class for the admin interface of derived models.
|
The *optional* base class for the admin interface of derived models.
|
||||||
|
|
@ -465,7 +447,6 @@ class PolymorphicChildModelAdmin(admin.ModelAdmin):
|
||||||
base_fieldsets = None
|
base_fieldsets = None
|
||||||
extra_fieldset_title = _("Contents") # Default title for extra fieldset
|
extra_fieldset_title = _("Contents") # Default title for extra fieldset
|
||||||
|
|
||||||
|
|
||||||
def get_form(self, request, obj=None, **kwargs):
|
def get_form(self, request, obj=None, **kwargs):
|
||||||
# The django admin validation requires the form to have a 'class Meta: model = ..'
|
# The django admin validation requires the form to have a 'class Meta: model = ..'
|
||||||
# attribute, or it will complain that the fields are missing.
|
# attribute, or it will complain that the fields are missing.
|
||||||
|
|
@ -482,7 +463,6 @@ class PolymorphicChildModelAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
return super(PolymorphicChildModelAdmin, self).get_form(request, obj, **kwargs)
|
return super(PolymorphicChildModelAdmin, self).get_form(request, obj, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def change_form_template(self):
|
def change_form_template(self):
|
||||||
opts = self.model._meta
|
opts = self.model._meta
|
||||||
|
|
@ -502,7 +482,6 @@ class PolymorphicChildModelAdmin(admin.ModelAdmin):
|
||||||
"admin/change_form.html"
|
"admin/change_form.html"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def delete_confirmation_template(self):
|
def delete_confirmation_template(self):
|
||||||
opts = self.model._meta
|
opts = self.model._meta
|
||||||
|
|
@ -522,21 +501,18 @@ class PolymorphicChildModelAdmin(admin.ModelAdmin):
|
||||||
"admin/delete_confirmation.html"
|
"admin/delete_confirmation.html"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
|
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
|
||||||
context.update({
|
context.update({
|
||||||
'base_opts': self.base_model._meta,
|
'base_opts': self.base_model._meta,
|
||||||
})
|
})
|
||||||
return super(PolymorphicChildModelAdmin, self).render_change_form(request, context, add=add, change=change, form_url=form_url, obj=obj)
|
return super(PolymorphicChildModelAdmin, self).render_change_form(request, context, add=add, change=change, form_url=form_url, obj=obj)
|
||||||
|
|
||||||
|
|
||||||
def delete_view(self, request, object_id, context=None):
|
def delete_view(self, request, object_id, context=None):
|
||||||
extra_context = {
|
extra_context = {
|
||||||
'base_opts': self.base_model._meta,
|
'base_opts': self.base_model._meta,
|
||||||
}
|
}
|
||||||
return super(PolymorphicChildModelAdmin, self).delete_view(request, object_id, extra_context)
|
return super(PolymorphicChildModelAdmin, self).delete_view(request, object_id, extra_context)
|
||||||
|
|
||||||
|
|
||||||
# ---- Extra: improving the form/fieldset default display ----
|
# ---- Extra: improving the form/fieldset default display ----
|
||||||
|
|
||||||
def get_fieldsets(self, request, obj=None):
|
def get_fieldsets(self, request, obj=None):
|
||||||
|
|
@ -557,7 +533,6 @@ class PolymorphicChildModelAdmin(admin.ModelAdmin):
|
||||||
else:
|
else:
|
||||||
return self.base_fieldsets
|
return self.base_fieldsets
|
||||||
|
|
||||||
|
|
||||||
def get_subclass_fields(self, request, obj=None):
|
def get_subclass_fields(self, request, obj=None):
|
||||||
# Find out how many fields would really be on the form,
|
# Find out how many fields would really be on the form,
|
||||||
# if it weren't restricted by declared fields.
|
# if it weren't restricted by declared fields.
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ from django.db import models
|
||||||
from django.db.models.base import ModelBase
|
from django.db.models.base import ModelBase
|
||||||
from django.db.models.manager import ManagerDescriptor
|
from django.db.models.manager import ManagerDescriptor
|
||||||
|
|
||||||
from .manager import PolymorphicManager
|
from .managers import PolymorphicManager
|
||||||
from .query import PolymorphicQuerySet
|
from .query import PolymorphicQuerySet
|
||||||
|
|
||||||
# PolymorphicQuerySet Q objects (and filter()) support these additional key words.
|
# PolymorphicQuerySet Q objects (and filter()) support these additional key words.
|
||||||
|
|
@ -26,7 +26,7 @@ except ImportError:
|
||||||
|
|
||||||
|
|
||||||
###################################################################################
|
###################################################################################
|
||||||
### PolymorphicModel meta class
|
# PolymorphicModel meta class
|
||||||
|
|
||||||
class PolymorphicModelBase(ModelBase):
|
class PolymorphicModelBase(ModelBase):
|
||||||
"""
|
"""
|
||||||
|
|
@ -53,11 +53,11 @@ class PolymorphicModelBase(ModelBase):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __new__(self, model_name, bases, attrs):
|
def __new__(self, model_name, bases, attrs):
|
||||||
#print; print '###', model_name, '- bases:', bases
|
# print; print '###', model_name, '- bases:', bases
|
||||||
|
|
||||||
# Workaround compatibility issue with six.with_metaclass() and custom Django model metaclasses:
|
# Workaround compatibility issue with six.with_metaclass() and custom Django model metaclasses:
|
||||||
if not attrs and model_name == 'NewBase':
|
if not attrs and model_name == 'NewBase':
|
||||||
if django.VERSION < (1,5):
|
if django.VERSION < (1, 5):
|
||||||
# Let Django fully ignore the class which is inserted in between.
|
# Let Django fully ignore the class which is inserted in between.
|
||||||
# Django 1.5 fixed this, see https://code.djangoproject.com/ticket/19688
|
# Django 1.5 fixed this, see https://code.djangoproject.com/ticket/19688
|
||||||
attrs['__module__'] = 'django.utils.six'
|
attrs['__module__'] = 'django.utils.six'
|
||||||
|
|
@ -75,7 +75,7 @@ class PolymorphicModelBase(ModelBase):
|
||||||
|
|
||||||
# add the managers to the new model
|
# add the managers to the new model
|
||||||
for source_name, mgr_name, manager in inherited_managers:
|
for source_name, mgr_name, manager in inherited_managers:
|
||||||
#print '** add inherited manager from model %s, manager %s, %s' % (source_name, mgr_name, manager.__class__.__name__)
|
# print '** add inherited manager from model %s, manager %s, %s' % (source_name, mgr_name, manager.__class__.__name__)
|
||||||
new_manager = manager._copy_to_model(new_class)
|
new_manager = manager._copy_to_model(new_class)
|
||||||
if mgr_name == '_default_manager':
|
if mgr_name == '_default_manager':
|
||||||
new_class._default_manager = new_manager
|
new_class._default_manager = new_manager
|
||||||
|
|
@ -86,7 +86,7 @@ class PolymorphicModelBase(ModelBase):
|
||||||
# this value is used by the related objects, restoring access to custom queryset methods on related objects.
|
# this value is used by the related objects, restoring access to custom queryset methods on related objects.
|
||||||
user_manager = self.get_first_user_defined_manager(new_class)
|
user_manager = self.get_first_user_defined_manager(new_class)
|
||||||
if user_manager:
|
if user_manager:
|
||||||
#print '## add default manager', type(def_mgr)
|
# print '## add default manager', type(def_mgr)
|
||||||
new_class._default_manager = user_manager._copy_to_model(new_class)
|
new_class._default_manager = user_manager._copy_to_model(new_class)
|
||||||
new_class._default_manager._inherited = False # the default mgr was defined by the user, not inherited
|
new_class._default_manager._inherited = False # the default mgr was defined by the user, not inherited
|
||||||
|
|
||||||
|
|
@ -111,7 +111,7 @@ class PolymorphicModelBase(ModelBase):
|
||||||
use correct mro, only use managers with _inherited==False (they are of no use),
|
use correct mro, only use managers with _inherited==False (they are of no use),
|
||||||
skip managers that are overwritten by the user with same-named class attributes (in attrs)
|
skip managers that are overwritten by the user with same-named class attributes (in attrs)
|
||||||
"""
|
"""
|
||||||
#print "** ", self.__name__
|
# print "** ", self.__name__
|
||||||
add_managers = []
|
add_managers = []
|
||||||
add_managers_keys = set()
|
add_managers_keys = set()
|
||||||
for base in self.__mro__[1:]:
|
for base in self.__mro__[1:]:
|
||||||
|
|
@ -147,7 +147,7 @@ class PolymorphicModelBase(ModelBase):
|
||||||
continue # manager with that name already added, skip
|
continue # manager with that name already added, skip
|
||||||
if manager._inherited:
|
if manager._inherited:
|
||||||
continue # inherited managers (on the bases) have no significance, they are just copies
|
continue # inherited managers (on the bases) have no significance, they are just copies
|
||||||
#print '## {0} {1}'.format(self.__name__, key)
|
# print '## {0} {1}'.format(self.__name__, key)
|
||||||
|
|
||||||
if isinstance(manager, PolymorphicManager): # validate any inherited polymorphic managers
|
if isinstance(manager, PolymorphicManager): # validate any inherited polymorphic managers
|
||||||
self.validate_model_manager(manager, self.__name__, key)
|
self.validate_model_manager(manager, self.__name__, key)
|
||||||
|
|
@ -175,7 +175,7 @@ class PolymorphicModelBase(ModelBase):
|
||||||
# if there are user defined managers, use first one as _default_manager
|
# if there are user defined managers, use first one as _default_manager
|
||||||
if mgr_list:
|
if mgr_list:
|
||||||
_, manager_name, manager = sorted(mgr_list)[0]
|
_, manager_name, manager = sorted(mgr_list)[0]
|
||||||
#sys.stderr.write( '\n# first user defined manager for model "{model}":\n# "{mgrname}": {mgr}\n# manager model: {mgrmodel}\n\n'
|
# sys.stderr.write( '\n# first user defined manager for model "{model}":\n# "{mgrname}": {mgr}\n# manager model: {mgrmodel}\n\n'
|
||||||
# .format( model=self.__name__, mgrname=manager_name, mgr=manager, mgrmodel=manager.model ) )
|
# .format( model=self.__name__, mgrname=manager_name, mgr=manager, mgrmodel=manager.model ) )
|
||||||
return manager
|
return manager
|
||||||
return None
|
return None
|
||||||
|
|
@ -191,9 +191,9 @@ class PolymorphicModelBase(ModelBase):
|
||||||
# app_label here for PolymorphicModel.
|
# app_label here for PolymorphicModel.
|
||||||
meta = attrs.get('Meta', None)
|
meta = attrs.get('Meta', None)
|
||||||
do_app_label_workaround = (meta
|
do_app_label_workaround = (meta
|
||||||
and attrs['__module__'] == 'polymorphic'
|
and attrs['__module__'] == 'polymorphic'
|
||||||
and model_name == 'PolymorphicModel'
|
and model_name == 'PolymorphicModel'
|
||||||
and getattr(meta, 'app_label', None) is None)
|
and getattr(meta, 'app_label', None) is None)
|
||||||
|
|
||||||
if do_app_label_workaround:
|
if do_app_label_workaround:
|
||||||
meta.app_label = 'poly_dummy_app_label'
|
meta.app_label = 'poly_dummy_app_label'
|
||||||
|
|
@ -241,8 +241,8 @@ class PolymorphicModelBase(ModelBase):
|
||||||
frm = inspect.stack()[1] # frm[1] is caller file name, frm[3] is caller function name
|
frm = inspect.stack()[1] # frm[1] is caller file name, frm[3] is caller function name
|
||||||
if 'django/core/management/commands/dumpdata.py' in frm[1]:
|
if 'django/core/management/commands/dumpdata.py' in frm[1]:
|
||||||
return self.base_objects
|
return self.base_objects
|
||||||
#caller_mod_name = inspect.getmodule(frm[0]).__name__ # does not work with python 2.4
|
# caller_mod_name = inspect.getmodule(frm[0]).__name__ # does not work with python 2.4
|
||||||
#if caller_mod_name == 'django.core.management.commands.dumpdata':
|
# if caller_mod_name == 'django.core.management.commands.dumpdata':
|
||||||
|
|
||||||
return super(PolymorphicModelBase, self).__getattribute__(name)
|
return super(PolymorphicModelBase, self).__getattribute__(name)
|
||||||
# TODO: investigate Django how this can be avoided
|
# TODO: investigate Django how this can be avoided
|
||||||
|
|
|
||||||
|
|
@ -1,55 +1,2 @@
|
||||||
# -*- coding: utf-8 -*-
|
# For compatibility with pre 0.8 versions
|
||||||
""" PolymorphicManager
|
from .managers import PolymorphicQuerySet, PolymorphicManager
|
||||||
Please see README.rst or DOCS.rst or http://chrisglass.github.com/django_polymorphic/
|
|
||||||
"""
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
import warnings
|
|
||||||
import django
|
|
||||||
from django.db import models
|
|
||||||
from polymorphic.query import PolymorphicQuerySet
|
|
||||||
|
|
||||||
|
|
||||||
class PolymorphicManager(models.Manager):
|
|
||||||
"""
|
|
||||||
Manager for PolymorphicModel
|
|
||||||
|
|
||||||
Usually not explicitly needed, except if a custom manager or
|
|
||||||
a custom queryset class is to be used.
|
|
||||||
"""
|
|
||||||
# Tell Django that related fields also need to use this manager:
|
|
||||||
use_for_related_fields = True
|
|
||||||
queryset_class = PolymorphicQuerySet
|
|
||||||
|
|
||||||
def __init__(self, queryset_class=None, *args, **kwrags):
|
|
||||||
# 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.
|
|
||||||
# Hence, for custom managers the new default is using the 'queryset_class' attribute at class level instead.
|
|
||||||
if queryset_class:
|
|
||||||
warnings.warn("Using PolymorphicManager(queryset_class=..) is deprecated; override the queryset_class attribute instead", DeprecationWarning)
|
|
||||||
# For backwards compatibility, still allow the parameter:
|
|
||||||
self.queryset_class = queryset_class
|
|
||||||
|
|
||||||
super(PolymorphicManager, self).__init__(*args, **kwrags)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return self.queryset_class(self.model, using=self._db)
|
|
||||||
|
|
||||||
# For Django 1.5
|
|
||||||
if django.VERSION < (1, 7):
|
|
||||||
get_query_set = get_queryset
|
|
||||||
|
|
||||||
# Proxy all unknown method calls to the queryset, so that its members are
|
|
||||||
# directly accessible as PolymorphicModel.objects.*
|
|
||||||
# The advantage of this method is that not yet known member functions of derived querysets will be proxied as well.
|
|
||||||
# We exclude any special functions (__) from this automatic proxying.
|
|
||||||
#
|
|
||||||
# NOTE: Fetching the queryset is done by calling self.all() here on purpose.
|
|
||||||
# By using .all(), the proper get_query_set()/get_queryset() will be used for each Django version.
|
|
||||||
# Django 1.4/1.5 need to use get_query_set(), because the RelatedManager overrides that.
|
|
||||||
def __getattr__(self, name):
|
|
||||||
if name.startswith('__'):
|
|
||||||
return super(PolymorphicManager, self).__getattr__(self, name)
|
|
||||||
return getattr(self.all(), name)
|
|
||||||
|
|
||||||
def __unicode__(self):
|
|
||||||
return '%s (PolymorphicManager) using %s' % (self.__class__.__name__, self.queryset_class.__name__)
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
""" PolymorphicManager
|
||||||
|
Please see README.rst or DOCS.rst or http://chrisglass.github.com/django_polymorphic/
|
||||||
|
"""
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import warnings
|
||||||
|
import django
|
||||||
|
from django.db import models
|
||||||
|
from polymorphic.query import PolymorphicQuerySet
|
||||||
|
|
||||||
|
|
||||||
|
class PolymorphicManager(models.Manager):
|
||||||
|
"""
|
||||||
|
Manager for PolymorphicModel
|
||||||
|
|
||||||
|
Usually not explicitly needed, except if a custom manager or
|
||||||
|
a custom queryset class is to be used.
|
||||||
|
"""
|
||||||
|
# Tell Django that related fields also need to use this manager:
|
||||||
|
use_for_related_fields = True
|
||||||
|
queryset_class = PolymorphicQuerySet
|
||||||
|
|
||||||
|
def __init__(self, queryset_class=None, *args, **kwrags):
|
||||||
|
# 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.
|
||||||
|
# Hence, for custom managers the new default is using the 'queryset_class' attribute at class level instead.
|
||||||
|
if queryset_class:
|
||||||
|
warnings.warn("Using PolymorphicManager(queryset_class=..) is deprecated; override the queryset_class attribute instead", DeprecationWarning)
|
||||||
|
# For backwards compatibility, still allow the parameter:
|
||||||
|
self.queryset_class = queryset_class
|
||||||
|
|
||||||
|
super(PolymorphicManager, self).__init__(*args, **kwrags)
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return self.queryset_class(self.model, using=self._db)
|
||||||
|
|
||||||
|
# For Django 1.5
|
||||||
|
if django.VERSION < (1, 7):
|
||||||
|
get_query_set = get_queryset
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return '%s (PolymorphicManager) using %s' % (self.__class__.__name__, self.queryset_class.__name__)
|
||||||
|
|
||||||
|
# Proxied methods
|
||||||
|
def non_polymorphic(self):
|
||||||
|
return self.all().non_polymorphic()
|
||||||
|
|
||||||
|
def instance_of(self, *args):
|
||||||
|
return self.all().instance_of(*args)
|
||||||
|
|
||||||
|
def not_instance_of(self, *args):
|
||||||
|
return self.all().not_instance_of(*args)
|
||||||
|
|
||||||
|
def get_real_instances(self, base_result_objects=None):
|
||||||
|
return self.all().get_real_instances(base_result_objects=base_result_objects)
|
||||||
|
|
@ -20,11 +20,12 @@ 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
|
||||||
from .manager import PolymorphicManager
|
from .managers import PolymorphicManager
|
||||||
from .query_translate import translate_polymorphic_Q_object
|
from .query_translate import translate_polymorphic_Q_object
|
||||||
|
|
||||||
###################################################################################
|
###################################################################################
|
||||||
### PolymorphicModel
|
# PolymorphicModel
|
||||||
|
|
||||||
|
|
||||||
class PolymorphicModel(six.with_metaclass(PolymorphicModelBase, models.Model)):
|
class PolymorphicModel(six.with_metaclass(PolymorphicModelBase, models.Model)):
|
||||||
"""
|
"""
|
||||||
|
|
@ -56,7 +57,7 @@ class PolymorphicModel(six.with_metaclass(PolymorphicModelBase, models.Model)):
|
||||||
|
|
||||||
# avoid ContentType related field accessor clash (an error emitted by model validation)
|
# avoid ContentType related field accessor clash (an error emitted by model validation)
|
||||||
polymorphic_ctype = models.ForeignKey(ContentType, null=True, editable=False,
|
polymorphic_ctype = models.ForeignKey(ContentType, null=True, editable=False,
|
||||||
related_name='polymorphic_%(app_label)s.%(class)s_set+')
|
related_name='polymorphic_%(app_label)s.%(class)s_set+')
|
||||||
|
|
||||||
# some applications want to know the name of the fields that are added to its models
|
# some applications want to know the name of the fields that are added to its models
|
||||||
polymorphic_internal_model_fields = ['polymorphic_ctype']
|
polymorphic_internal_model_fields = ['polymorphic_ctype']
|
||||||
|
|
@ -110,8 +111,8 @@ class PolymorphicModel(six.with_metaclass(PolymorphicModelBase, models.Model)):
|
||||||
# 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.
|
||||||
if model is not None \
|
if model is not None \
|
||||||
and not issubclass(model, self.__class__) \
|
and not issubclass(model, self.__class__) \
|
||||||
and not issubclass(model, self.__class__._meta.proxy_for_model):
|
and not issubclass(model, self.__class__._meta.proxy_for_model):
|
||||||
raise RuntimeError("ContentType {0} for {1} #{2} does not point to a subclass!".format(
|
raise RuntimeError("ContentType {0} for {1} #{2} does not point to a subclass!".format(
|
||||||
self.polymorphic_ctype_id, model, self.pk,
|
self.polymorphic_ctype_id, model, self.pk,
|
||||||
))
|
))
|
||||||
|
|
@ -196,29 +197,29 @@ class PolymorphicModel(six.with_metaclass(PolymorphicModelBase, models.Model)):
|
||||||
|
|
||||||
def add_model_if_regular(model, field_name, result):
|
def add_model_if_regular(model, field_name, result):
|
||||||
if (issubclass(model, models.Model)
|
if (issubclass(model, models.Model)
|
||||||
and model != models.Model
|
and model != models.Model
|
||||||
and model != self.__class__
|
and model != self.__class__
|
||||||
and model != PolymorphicModel):
|
and model != PolymorphicModel):
|
||||||
add_model(model, field_name, result)
|
add_model(model, field_name, result)
|
||||||
|
|
||||||
def add_all_super_models(model, result):
|
def add_all_super_models(model, result):
|
||||||
for super_cls, field_to_super in model._meta.parents.items():
|
for super_cls, field_to_super in model._meta.parents.items():
|
||||||
if field_to_super is not None: #if not a link to a proxy model
|
if field_to_super is not None: # if not a link to a proxy model
|
||||||
field_name = field_to_super.name #the field on model can have a different name to super_cls._meta.module_name, if the field is created manually using 'parent_link'
|
field_name = field_to_super.name # the field on model can have a different name to super_cls._meta.module_name, if the field is created manually using 'parent_link'
|
||||||
add_model_if_regular(super_cls, field_name, result)
|
add_model_if_regular(super_cls, field_name, result)
|
||||||
add_all_super_models(super_cls, result)
|
add_all_super_models(super_cls, result)
|
||||||
|
|
||||||
def add_all_sub_models(super_cls, result):
|
def add_all_sub_models(super_cls, result):
|
||||||
for sub_cls in super_cls.__subclasses__(): #go through all subclasses of model
|
for sub_cls in super_cls.__subclasses__(): # go through all subclasses of model
|
||||||
if super_cls in sub_cls._meta.parents: #super_cls may not be in sub_cls._meta.parents if super_cls is a proxy model
|
if super_cls in sub_cls._meta.parents: # super_cls may not be in sub_cls._meta.parents if super_cls is a proxy model
|
||||||
field_to_super = sub_cls._meta.parents[super_cls] #get the field that links sub_cls to super_cls
|
field_to_super = sub_cls._meta.parents[super_cls] # get the field that links sub_cls to super_cls
|
||||||
if field_to_super is not None: # if filed_to_super is not a link to a proxy model
|
if field_to_super is not None: # if filed_to_super is not a link to a proxy model
|
||||||
super_to_sub_related_field = field_to_super.rel
|
super_to_sub_related_field = field_to_super.rel
|
||||||
if super_to_sub_related_field.related_name is None:
|
if super_to_sub_related_field.related_name is None:
|
||||||
#if related name is None the related field is the name of the subclass
|
# if related name is None the related field is the name of the subclass
|
||||||
to_subclass_fieldname = sub_cls.__name__.lower()
|
to_subclass_fieldname = sub_cls.__name__.lower()
|
||||||
else:
|
else:
|
||||||
#otherwise use the given related name
|
# otherwise use the given related name
|
||||||
to_subclass_fieldname = super_to_sub_related_field.related_name
|
to_subclass_fieldname = super_to_sub_related_field.related_name
|
||||||
|
|
||||||
add_model_if_regular(sub_cls, to_subclass_fieldname, result)
|
add_model_if_regular(sub_cls, to_subclass_fieldname, result)
|
||||||
|
|
|
||||||
|
|
@ -35,13 +35,13 @@ def transmogrify(cls, obj):
|
||||||
else:
|
else:
|
||||||
# Run constructor, reassign values
|
# Run constructor, reassign values
|
||||||
new = cls()
|
new = cls()
|
||||||
for k,v in obj.__dict__.items():
|
for k, v in obj.__dict__.items():
|
||||||
new.__dict__[k] = v
|
new.__dict__[k] = v
|
||||||
return new
|
return new
|
||||||
|
|
||||||
|
|
||||||
###################################################################################
|
###################################################################################
|
||||||
### PolymorphicQuerySet
|
# PolymorphicQuerySet
|
||||||
|
|
||||||
def _query_annotations(query):
|
def _query_annotations(query):
|
||||||
try:
|
try:
|
||||||
|
|
@ -72,17 +72,17 @@ class PolymorphicQuerySet(QuerySet):
|
||||||
new.polymorphic_disabled = self.polymorphic_disabled
|
new.polymorphic_disabled = self.polymorphic_disabled
|
||||||
return new
|
return new
|
||||||
|
|
||||||
if django.VERSION >= (1,7):
|
if django.VERSION >= (1, 7):
|
||||||
def as_manager(cls):
|
def as_manager(cls):
|
||||||
# Make sure the Django 1.7 way of creating managers works.
|
# Make sure the Django 1.7 way of creating managers works.
|
||||||
from .manager import PolymorphicManager
|
from .managers import PolymorphicManager
|
||||||
manager = PolymorphicManager.from_queryset(cls)()
|
manager = PolymorphicManager.from_queryset(cls)()
|
||||||
manager._built_with_as_manager = True
|
manager._built_with_as_manager = True
|
||||||
return manager
|
return manager
|
||||||
as_manager.queryset_only = True
|
as_manager.queryset_only = True
|
||||||
as_manager = classmethod(as_manager)
|
as_manager = classmethod(as_manager)
|
||||||
|
|
||||||
def non_polymorphic(self, *args, **kwargs):
|
def non_polymorphic(self):
|
||||||
"""switch off polymorphic behaviour for this query.
|
"""switch off polymorphic behaviour for this query.
|
||||||
When the queryset is evaluated, only objects of the type of the
|
When the queryset is evaluated, only objects of the type of the
|
||||||
base class used for this query are returned."""
|
base class used for this query are returned."""
|
||||||
|
|
@ -160,7 +160,7 @@ class PolymorphicQuerySet(QuerySet):
|
||||||
# The resulting objects are required to have a unique primary key within the result set
|
# The resulting objects are required to have a unique primary key within the result set
|
||||||
# (otherwise an error is thrown).
|
# (otherwise an error is thrown).
|
||||||
# The "polymorphic" keyword argument is not supported anymore.
|
# The "polymorphic" keyword argument is not supported anymore.
|
||||||
#def extra(self, *args, **kwargs):
|
# def extra(self, *args, **kwargs):
|
||||||
|
|
||||||
def _get_real_instances(self, base_result_objects):
|
def _get_real_instances(self, base_result_objects):
|
||||||
"""
|
"""
|
||||||
|
|
@ -333,14 +333,15 @@ class PolymorphicQuerySet(QuerySet):
|
||||||
def __repr__(self, *args, **kwargs):
|
def __repr__(self, *args, **kwargs):
|
||||||
if self.model.polymorphic_query_multiline_output:
|
if self.model.polymorphic_query_multiline_output:
|
||||||
result = [repr(o) for o in self.all()]
|
result = [repr(o) for o in self.all()]
|
||||||
return '[ ' + ',\n '.join(result) + ' ]'
|
return '[ ' + ',\n '.join(result) + ' ]'
|
||||||
else:
|
else:
|
||||||
return super(PolymorphicQuerySet, self).__repr__(*args, **kwargs)
|
return super(PolymorphicQuerySet, self).__repr__(*args, **kwargs)
|
||||||
|
|
||||||
class _p_list_class(list):
|
class _p_list_class(list):
|
||||||
|
|
||||||
def __repr__(self, *args, **kwargs):
|
def __repr__(self, *args, **kwargs):
|
||||||
result = [repr(o) for o in self]
|
result = [repr(o) for o in self]
|
||||||
return '[ ' + ',\n '.join(result) + ' ]'
|
return '[ ' + ',\n '.join(result) + ' ]'
|
||||||
|
|
||||||
def get_real_instances(self, base_result_objects=None):
|
def get_real_instances(self, base_result_objects=None):
|
||||||
"same as _get_real_instances, but make sure that __repr__ for ShowField... creates correct output"
|
"same as _get_real_instances, but make sure that __repr__ for ShowField... creates correct output"
|
||||||
|
|
|
||||||
|
|
@ -4,24 +4,31 @@
|
||||||
"""
|
"""
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import django
|
||||||
from django.db import models
|
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.models import Q, FieldDoesNotExist
|
||||||
|
|
||||||
try:
|
from django.db.models.fields.related import RelatedField
|
||||||
from django.db.models.related import RelatedObject
|
if django.VERSION < (1, 6):
|
||||||
except ImportError:
|
# There was no common base class in Django 1.5, mention all variants here.
|
||||||
# django.db.models.related.RelatedObject was replaced
|
from django.db.models.fields.related import RelatedObject, ManyToOneRel, ManyToManyRel
|
||||||
# by django.db.models.fields.related.ForeignObjectRel in
|
REL_FIELD_CLASSES = (RelatedField, RelatedObject, ManyToOneRel, ManyToManyRel) # Leaving GenericRel out.
|
||||||
# Django 1.8
|
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
|
from django.db.models.fields.related import ForeignObjectRel
|
||||||
RelatedObject = ForeignObjectRel
|
REL_FIELD_CLASSES = (RelatedField, ForeignObjectRel)
|
||||||
|
|
||||||
|
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
|
||||||
|
|
||||||
###################################################################################
|
###################################################################################
|
||||||
### PolymorphicQuerySet support functions
|
# PolymorphicQuerySet support functions
|
||||||
|
|
||||||
# These functions implement the additional filter- and Q-object functionality.
|
# These functions implement the additional filter- and Q-object functionality.
|
||||||
# They form a kind of small framework for easily adding more
|
# They form a kind of small framework for easily adding more
|
||||||
|
|
@ -161,9 +168,13 @@ 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:
|
||||||
# rel = (field_object, model, direct, m2m)
|
if django.VERSION >= (1, 8):
|
||||||
field = queryset_model._meta.get_field(classname)
|
# This also retreives M2M relations now (including reverse foreign key relations)
|
||||||
if isinstance(field, RelatedObject):
|
field = queryset_model._meta.get_field(classname)
|
||||||
|
else:
|
||||||
|
field = queryset_model._meta.get_field_by_name(classname)[0]
|
||||||
|
|
||||||
|
if isinstance(field, REL_FIELD_CLASSES):
|
||||||
# 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.
|
||||||
|
|
@ -248,7 +259,7 @@ def _create_model_filter_Q(modellist, not_instance_of=False):
|
||||||
q = q | q_class_with_subclasses(subclass)
|
q = q | q_class_with_subclasses(subclass)
|
||||||
return q
|
return q
|
||||||
|
|
||||||
qlist = [q_class_with_subclasses(m) for m in modellist]
|
qlist = [q_class_with_subclasses(m) for m in modellist]
|
||||||
|
|
||||||
q_ored = reduce(lambda a, b: a | b, qlist)
|
q_ored = reduce(lambda a, b: a | b, qlist)
|
||||||
if not_instance_of:
|
if not_instance_of:
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
|
|
||||||
class ShowFieldBase(object):
|
class ShowFieldBase(object):
|
||||||
""" base class for the ShowField... model mixins, does the work """
|
""" base class for the ShowField... model mixins, does the work """
|
||||||
|
|
||||||
|
|
@ -119,8 +120,8 @@ class ShowFieldBase(object):
|
||||||
next_new_section, _, _ = parts[i + 1]
|
next_new_section, _, _ = parts[i + 1]
|
||||||
|
|
||||||
if (self.polymorphic_showfield_max_line_width
|
if (self.polymorphic_showfield_max_line_width
|
||||||
and xpos + len(p) > self.polymorphic_showfield_max_line_width
|
and xpos + len(p) > self.polymorphic_showfield_max_line_width
|
||||||
and possible_line_break_pos != None):
|
and possible_line_break_pos != None):
|
||||||
rest = out[possible_line_break_pos:]
|
rest = out[possible_line_break_pos:]
|
||||||
out = out[:possible_line_break_pos]
|
out = out[:possible_line_break_pos]
|
||||||
out += '\n' + indentstr + rest
|
out += '\n' + indentstr + rest
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ register = Library()
|
||||||
|
|
||||||
|
|
||||||
class BreadcrumbScope(Node):
|
class BreadcrumbScope(Node):
|
||||||
|
|
||||||
def __init__(self, base_opts, nodelist):
|
def __init__(self, base_opts, nodelist):
|
||||||
self.base_opts = base_opts
|
self.base_opts = base_opts
|
||||||
self.nodelist = nodelist # Note, takes advantage of Node.child_nodelists
|
self.nodelist = nodelist # Note, takes advantage of Node.child_nodelists
|
||||||
|
|
@ -25,7 +26,6 @@ class BreadcrumbScope(Node):
|
||||||
else:
|
else:
|
||||||
raise TemplateSyntaxError("{0} tag expects 1 argument".format(token.contents[0]))
|
raise TemplateSyntaxError("{0} tag expects 1 argument".format(token.contents[0]))
|
||||||
|
|
||||||
|
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
# app_label is really hard to overwrite in the standard Django ModelAdmin.
|
# app_label is really hard to overwrite in the standard Django ModelAdmin.
|
||||||
# To insert it in the template, the entire render_change_form() and delete_view() have to copied and adjusted.
|
# To insert it in the template, the entire render_change_form() and delete_view() have to copied and adjusted.
|
||||||
|
|
|
||||||
|
|
@ -14,15 +14,15 @@ except ImportError:
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.db.models import Q,Count
|
from django.db.models import Q, Count
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
from polymorphic.models import PolymorphicModel
|
from polymorphic.models import PolymorphicModel
|
||||||
from polymorphic.manager import PolymorphicManager
|
from polymorphic.managers import PolymorphicManager
|
||||||
from polymorphic.query import PolymorphicQuerySet
|
from polymorphic.query import PolymorphicQuerySet
|
||||||
from polymorphic import ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent
|
from polymorphic.showfields import ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent
|
||||||
try:
|
try:
|
||||||
from django.db.models import UUIDField
|
from django.db.models import UUIDField
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
|
@ -32,94 +32,156 @@ except ImportError:
|
||||||
|
|
||||||
class PlainA(models.Model):
|
class PlainA(models.Model):
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class PlainB(PlainA):
|
class PlainB(PlainA):
|
||||||
field2 = models.CharField(max_length=10)
|
field2 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class PlainC(PlainB):
|
class PlainC(PlainB):
|
||||||
field3 = models.CharField(max_length=10)
|
field3 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class Model2A(ShowFieldType, PolymorphicModel):
|
class Model2A(ShowFieldType, PolymorphicModel):
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class Model2B(Model2A):
|
class Model2B(Model2A):
|
||||||
field2 = models.CharField(max_length=10)
|
field2 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class Model2C(Model2B):
|
class Model2C(Model2B):
|
||||||
field3 = models.CharField(max_length=10)
|
field3 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class Model2D(Model2C):
|
class Model2D(Model2C):
|
||||||
field4 = models.CharField(max_length=10)
|
field4 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class ModelExtraA(ShowFieldTypeAndContent, PolymorphicModel):
|
class ModelExtraA(ShowFieldTypeAndContent, PolymorphicModel):
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class ModelExtraB(ModelExtraA):
|
class ModelExtraB(ModelExtraA):
|
||||||
field2 = models.CharField(max_length=10)
|
field2 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class ModelExtraC(ModelExtraB):
|
class ModelExtraC(ModelExtraB):
|
||||||
field3 = models.CharField(max_length=10)
|
field3 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class ModelExtraExternal(models.Model):
|
class ModelExtraExternal(models.Model):
|
||||||
topic = models.CharField(max_length=10)
|
topic = models.CharField(max_length=10)
|
||||||
|
|
||||||
class ModelShow1(ShowFieldType,PolymorphicModel):
|
|
||||||
|
class ModelShow1(ShowFieldType, PolymorphicModel):
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
m2m = models.ManyToManyField('self')
|
m2m = models.ManyToManyField('self')
|
||||||
|
|
||||||
|
|
||||||
class ModelShow2(ShowFieldContent, PolymorphicModel):
|
class ModelShow2(ShowFieldContent, PolymorphicModel):
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
m2m = models.ManyToManyField('self')
|
m2m = models.ManyToManyField('self')
|
||||||
|
|
||||||
|
|
||||||
class ModelShow3(ShowFieldTypeAndContent, PolymorphicModel):
|
class ModelShow3(ShowFieldTypeAndContent, PolymorphicModel):
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
m2m = models.ManyToManyField('self')
|
m2m = models.ManyToManyField('self')
|
||||||
|
|
||||||
|
|
||||||
class ModelShow1_plain(PolymorphicModel):
|
class ModelShow1_plain(PolymorphicModel):
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class ModelShow2_plain(ModelShow1_plain):
|
class ModelShow2_plain(ModelShow1_plain):
|
||||||
field2 = models.CharField(max_length=10)
|
field2 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class Base(ShowFieldType, PolymorphicModel):
|
class Base(ShowFieldType, PolymorphicModel):
|
||||||
field_b = models.CharField(max_length=10)
|
field_b = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class ModelX(Base):
|
class ModelX(Base):
|
||||||
field_x = models.CharField(max_length=10)
|
field_x = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class ModelY(Base):
|
class ModelY(Base):
|
||||||
field_y = models.CharField(max_length=10)
|
field_y = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class Enhance_Plain(models.Model):
|
class Enhance_Plain(models.Model):
|
||||||
field_p = models.CharField(max_length=10)
|
field_p = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class Enhance_Base(ShowFieldTypeAndContent, PolymorphicModel):
|
class Enhance_Base(ShowFieldTypeAndContent, PolymorphicModel):
|
||||||
base_id = models.AutoField(primary_key=True)
|
base_id = models.AutoField(primary_key=True)
|
||||||
field_b = models.CharField(max_length=10)
|
field_b = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class Enhance_Inherit(Enhance_Base, Enhance_Plain):
|
class Enhance_Inherit(Enhance_Base, Enhance_Plain):
|
||||||
field_i = models.CharField(max_length=10)
|
field_i = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class RelationBase(ShowFieldTypeAndContent, PolymorphicModel):
|
class RelationBase(ShowFieldTypeAndContent, PolymorphicModel):
|
||||||
field_base = models.CharField(max_length=10)
|
field_base = models.CharField(max_length=10)
|
||||||
fk = models.ForeignKey('self', null=True, related_name='relationbase_set')
|
fk = models.ForeignKey('self', null=True, related_name='relationbase_set')
|
||||||
m2m = models.ManyToManyField('self')
|
m2m = models.ManyToManyField('self')
|
||||||
|
|
||||||
|
|
||||||
class RelationA(RelationBase):
|
class RelationA(RelationBase):
|
||||||
field_a = models.CharField(max_length=10)
|
field_a = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class RelationB(RelationBase):
|
class RelationB(RelationBase):
|
||||||
field_b = models.CharField(max_length=10)
|
field_b = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class RelationBC(RelationB):
|
class RelationBC(RelationB):
|
||||||
field_c = models.CharField(max_length=10)
|
field_c = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class RelatingModel(models.Model):
|
class RelatingModel(models.Model):
|
||||||
many2many = models.ManyToManyField(Model2A)
|
many2many = models.ManyToManyField(Model2A)
|
||||||
|
|
||||||
|
|
||||||
class One2OneRelatingModel(PolymorphicModel):
|
class One2OneRelatingModel(PolymorphicModel):
|
||||||
one2one = models.OneToOneField(Model2A)
|
one2one = models.OneToOneField(Model2A)
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class One2OneRelatingModelDerived(One2OneRelatingModel):
|
class One2OneRelatingModelDerived(One2OneRelatingModel):
|
||||||
field2 = models.CharField(max_length=10)
|
field2 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
|
class ModelUnderRelParent(PolymorphicModel):
|
||||||
|
field1 = models.CharField(max_length=10)
|
||||||
|
_private = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
|
class ModelUnderRelChild(PolymorphicModel):
|
||||||
|
parent = models.ForeignKey(ModelUnderRelParent, related_name='children')
|
||||||
|
_private2 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class MyManagerQuerySet(PolymorphicQuerySet):
|
class MyManagerQuerySet(PolymorphicQuerySet):
|
||||||
|
|
||||||
def my_queryset_foo(self):
|
def my_queryset_foo(self):
|
||||||
return self.all() # Just a method to prove the existance of the custom queryset.
|
return self.all() # Just a method to prove the existance of the custom queryset.
|
||||||
|
|
||||||
|
|
||||||
class MyManager(PolymorphicManager):
|
class MyManager(PolymorphicManager):
|
||||||
queryset_class = MyManagerQuerySet
|
queryset_class = MyManagerQuerySet
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return super(MyManager, self).get_queryset().order_by('-field1')
|
return super(MyManager, self).get_queryset().order_by('-field1')
|
||||||
|
|
||||||
|
def my_queryset_foo(self):
|
||||||
|
return self.all().my_queryset_foo()
|
||||||
|
|
||||||
# Django <= 1.5 compatibility
|
# Django <= 1.5 compatibility
|
||||||
get_query_set = get_queryset
|
get_query_set = get_queryset
|
||||||
|
|
||||||
|
|
||||||
class ModelWithMyManager(ShowFieldTypeAndContent, Model2A):
|
class ModelWithMyManager(ShowFieldTypeAndContent, Model2A):
|
||||||
objects = MyManager()
|
objects = MyManager()
|
||||||
field4 = models.CharField(max_length=10)
|
field4 = models.CharField(max_length=10)
|
||||||
|
|
@ -136,23 +198,33 @@ class ModelWithMyManagerDefault(ShowFieldTypeAndContent, Model2A):
|
||||||
field4 = models.CharField(max_length=10)
|
field4 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
if django.VERSION >= (1,7):
|
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):
|
||||||
objects = MyManager()
|
objects = MyManager()
|
||||||
field1 = models.CharField(max_length=10) # needed as MyManager uses it
|
field1 = models.CharField(max_length=10) # needed as MyManager uses it
|
||||||
|
|
||||||
|
|
||||||
class MROBase2(MROBase1):
|
class MROBase2(MROBase1):
|
||||||
pass # Django vanilla inheritance does not inherit MyManager as _default_manager here
|
pass # Django vanilla inheritance does not inherit MyManager as _default_manager here
|
||||||
|
|
||||||
|
|
||||||
class MROBase3(models.Model):
|
class MROBase3(models.Model):
|
||||||
objects = PolymorphicManager()
|
objects = PolymorphicManager()
|
||||||
|
|
||||||
|
|
||||||
class MRODerived(MROBase2, MROBase3):
|
class MRODerived(MROBase2, MROBase3):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ParentModelWithManager(PolymorphicModel):
|
class ParentModelWithManager(PolymorphicModel):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ChildModelWithManager(PolymorphicModel):
|
class ChildModelWithManager(PolymorphicModel):
|
||||||
# Also test whether foreign keys receive the manager:
|
# Also test whether foreign keys receive the manager:
|
||||||
fk = models.ForeignKey(ParentModelWithManager, related_name='childmodel_set')
|
fk = models.ForeignKey(ParentModelWithManager, related_name='childmodel_set')
|
||||||
|
|
@ -160,10 +232,13 @@ class ChildModelWithManager(PolymorphicModel):
|
||||||
|
|
||||||
|
|
||||||
class PlainMyManagerQuerySet(QuerySet):
|
class PlainMyManagerQuerySet(QuerySet):
|
||||||
|
|
||||||
def my_queryset_foo(self):
|
def my_queryset_foo(self):
|
||||||
return self.all() # Just a method to prove the existance of the custom queryset.
|
return self.all() # Just a method to prove the existance of the custom queryset.
|
||||||
|
|
||||||
|
|
||||||
class PlainMyManager(models.Manager):
|
class PlainMyManager(models.Manager):
|
||||||
|
|
||||||
def my_queryset_foo(self):
|
def my_queryset_foo(self):
|
||||||
return self.get_queryset().my_queryset_foo()
|
return self.get_queryset().my_queryset_foo()
|
||||||
|
|
||||||
|
|
@ -173,9 +248,11 @@ class PlainMyManager(models.Manager):
|
||||||
# Django <= 1.5 compatibility
|
# Django <= 1.5 compatibility
|
||||||
get_query_set = get_queryset
|
get_query_set = get_queryset
|
||||||
|
|
||||||
|
|
||||||
class PlainParentModelWithManager(models.Model):
|
class PlainParentModelWithManager(models.Model):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class PlainChildModelWithManager(models.Model):
|
class PlainChildModelWithManager(models.Model):
|
||||||
fk = models.ForeignKey(PlainParentModelWithManager, related_name='childmodel_set')
|
fk = models.ForeignKey(PlainParentModelWithManager, related_name='childmodel_set')
|
||||||
objects = PlainMyManager()
|
objects = PlainMyManager()
|
||||||
|
|
@ -185,88 +262,138 @@ class MgrInheritA(models.Model):
|
||||||
mgrA = models.Manager()
|
mgrA = models.Manager()
|
||||||
mgrA2 = models.Manager()
|
mgrA2 = models.Manager()
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class MgrInheritB(MgrInheritA):
|
class MgrInheritB(MgrInheritA):
|
||||||
mgrB = models.Manager()
|
mgrB = models.Manager()
|
||||||
field2 = models.CharField(max_length=10)
|
field2 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class MgrInheritC(ShowFieldTypeAndContent, MgrInheritB):
|
class MgrInheritC(ShowFieldTypeAndContent, MgrInheritB):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BlogBase(ShowFieldTypeAndContent, PolymorphicModel):
|
class BlogBase(ShowFieldTypeAndContent, PolymorphicModel):
|
||||||
name = models.CharField(max_length=10)
|
name = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class BlogA(BlogBase):
|
class BlogA(BlogBase):
|
||||||
info = models.CharField(max_length=10)
|
info = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class BlogB(BlogBase):
|
class BlogB(BlogBase):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BlogEntry(ShowFieldTypeAndContent, PolymorphicModel):
|
class BlogEntry(ShowFieldTypeAndContent, PolymorphicModel):
|
||||||
blog = models.ForeignKey(BlogA)
|
blog = models.ForeignKey(BlogA)
|
||||||
text = models.CharField(max_length=10)
|
text = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class BlogEntry_limit_choices_to(ShowFieldTypeAndContent, PolymorphicModel):
|
class BlogEntry_limit_choices_to(ShowFieldTypeAndContent, PolymorphicModel):
|
||||||
blog = models.ForeignKey(BlogBase)
|
blog = models.ForeignKey(BlogBase)
|
||||||
text = models.CharField(max_length=10)
|
text = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class ModelFieldNameTest(ShowFieldType, PolymorphicModel):
|
class ModelFieldNameTest(ShowFieldType, PolymorphicModel):
|
||||||
modelfieldnametest = models.CharField(max_length=10)
|
modelfieldnametest = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class InitTestModel(ShowFieldType, PolymorphicModel):
|
class InitTestModel(ShowFieldType, PolymorphicModel):
|
||||||
bar = models.CharField(max_length=100)
|
bar = models.CharField(max_length=100)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
kwargs['bar'] = self.x()
|
kwargs['bar'] = self.x()
|
||||||
super(InitTestModel, self).__init__(*args, **kwargs)
|
super(InitTestModel, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class InitTestModelSubclass(InitTestModel):
|
class InitTestModelSubclass(InitTestModel):
|
||||||
|
|
||||||
def x(self):
|
def x(self):
|
||||||
return 'XYZ'
|
return 'XYZ'
|
||||||
|
|
||||||
# models from github issue
|
# models from github issue
|
||||||
|
|
||||||
|
|
||||||
class Top(PolymorphicModel):
|
class Top(PolymorphicModel):
|
||||||
name = models.CharField(max_length=50)
|
name = models.CharField(max_length=50)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('pk',)
|
ordering = ('pk',)
|
||||||
|
|
||||||
|
|
||||||
class Middle(Top):
|
class Middle(Top):
|
||||||
description = models.TextField()
|
description = models.TextField()
|
||||||
|
|
||||||
|
|
||||||
class Bottom(Middle):
|
class Bottom(Middle):
|
||||||
author = models.CharField(max_length=50)
|
author = models.CharField(max_length=50)
|
||||||
|
|
||||||
|
|
||||||
class UUIDProject(ShowFieldTypeAndContent, PolymorphicModel):
|
class UUIDProject(ShowFieldTypeAndContent, PolymorphicModel):
|
||||||
uuid_primary_key = UUIDField(primary_key = True, default=uuid.uuid1)
|
uuid_primary_key = UUIDField(primary_key=True, default=uuid.uuid1)
|
||||||
topic = models.CharField(max_length = 30)
|
topic = models.CharField(max_length=30)
|
||||||
|
|
||||||
|
|
||||||
class UUIDArtProject(UUIDProject):
|
class UUIDArtProject(UUIDProject):
|
||||||
artist = models.CharField(max_length = 30)
|
artist = models.CharField(max_length=30)
|
||||||
|
|
||||||
|
|
||||||
class UUIDResearchProject(UUIDProject):
|
class UUIDResearchProject(UUIDProject):
|
||||||
supervisor = models.CharField(max_length = 30)
|
supervisor = models.CharField(max_length=30)
|
||||||
|
|
||||||
|
|
||||||
class UUIDPlainA(models.Model):
|
class UUIDPlainA(models.Model):
|
||||||
uuid_primary_key = UUIDField(primary_key = True, default=uuid.uuid1)
|
uuid_primary_key = UUIDField(primary_key=True, default=uuid.uuid1)
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class UUIDPlainB(UUIDPlainA):
|
class UUIDPlainB(UUIDPlainA):
|
||||||
field2 = models.CharField(max_length=10)
|
field2 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class UUIDPlainC(UUIDPlainB):
|
class UUIDPlainC(UUIDPlainB):
|
||||||
field3 = models.CharField(max_length=10)
|
field3 = models.CharField(max_length=10)
|
||||||
|
|
||||||
# base -> proxy
|
# base -> proxy
|
||||||
|
|
||||||
|
|
||||||
class ProxyBase(PolymorphicModel):
|
class ProxyBase(PolymorphicModel):
|
||||||
some_data = models.CharField(max_length=128)
|
some_data = models.CharField(max_length=128)
|
||||||
|
|
||||||
|
|
||||||
class ProxyChild(ProxyBase):
|
class ProxyChild(ProxyBase):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
proxy = True
|
proxy = True
|
||||||
|
|
||||||
|
|
||||||
class NonProxyChild(ProxyBase):
|
class NonProxyChild(ProxyBase):
|
||||||
name=models.CharField(max_length=10)
|
name = models.CharField(max_length=10)
|
||||||
|
|
||||||
# base -> proxy -> real models
|
# base -> proxy -> real models
|
||||||
|
|
||||||
|
|
||||||
class ProxiedBase(ShowFieldTypeAndContent, PolymorphicModel):
|
class ProxiedBase(ShowFieldTypeAndContent, PolymorphicModel):
|
||||||
name = models.CharField(max_length=10)
|
name = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class ProxyModelBase(ProxiedBase):
|
class ProxyModelBase(ProxiedBase):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
proxy = True
|
proxy = True
|
||||||
|
|
||||||
|
|
||||||
class ProxyModelA(ProxyModelBase):
|
class ProxyModelA(ProxyModelBase):
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
class ProxyModelB(ProxyModelBase):
|
class ProxyModelB(ProxyModelBase):
|
||||||
field2 = models.CharField(max_length=10)
|
field2 = models.CharField(max_length=10)
|
||||||
|
|
||||||
|
|
||||||
# test bad field name
|
# test bad field name
|
||||||
#class TestBadFieldModel(ShowFieldType, PolymorphicModel):
|
# class TestBadFieldModel(ShowFieldType, PolymorphicModel):
|
||||||
# instance_of = models.CharField(max_length=10)
|
# instance_of = models.CharField(max_length=10)
|
||||||
|
|
||||||
# validation error: "polymorphic.relatednameclash: Accessor for field 'polymorphic_ctype' clashes
|
# validation error: "polymorphic.relatednameclash: Accessor for field 'polymorphic_ctype' clashes
|
||||||
|
|
@ -275,12 +402,17 @@ class ProxyModelB(ProxyModelBase):
|
||||||
class RelatedNameClash(ShowFieldType, PolymorphicModel):
|
class RelatedNameClash(ShowFieldType, PolymorphicModel):
|
||||||
ctype = models.ForeignKey(ContentType, null=True, editable=False)
|
ctype = models.ForeignKey(ContentType, null=True, editable=False)
|
||||||
|
|
||||||
#class with a parent_link to superclass, and a related_name back to subclass
|
# class with a parent_link to superclass, and a related_name back to subclass
|
||||||
|
|
||||||
|
|
||||||
class TestParentLinkAndRelatedName(ModelShow1_plain):
|
class TestParentLinkAndRelatedName(ModelShow1_plain):
|
||||||
superclass = models.OneToOneField(ModelShow1_plain, parent_link=True, related_name='related_name_subclass')
|
superclass = models.OneToOneField(ModelShow1_plain, parent_link=True, related_name='related_name_subclass')
|
||||||
|
|
||||||
|
|
||||||
class CustomPkBase(ShowFieldTypeAndContent, PolymorphicModel):
|
class CustomPkBase(ShowFieldTypeAndContent, PolymorphicModel):
|
||||||
b = models.CharField(max_length=1)
|
b = models.CharField(max_length=1)
|
||||||
|
|
||||||
|
|
||||||
class CustomPkInherit(CustomPkBase):
|
class CustomPkInherit(CustomPkBase):
|
||||||
custom_id = models.AutoField(primary_key=True)
|
custom_id = models.AutoField(primary_key=True)
|
||||||
i = models.CharField(max_length=1)
|
i = models.CharField(max_length=1)
|
||||||
|
|
@ -335,7 +467,7 @@ class PolymorphicTests(TestCase):
|
||||||
|
|
||||||
# test ordering for field in one subclass only
|
# test ordering for field in one subclass only
|
||||||
# MySQL and SQLite return this order
|
# MySQL and SQLite return this order
|
||||||
expected1='''
|
expected1 = '''
|
||||||
[ <BlogA: id 8, name (CharField) "B5", info (CharField) "i5">,
|
[ <BlogA: id 8, name (CharField) "B5", info (CharField) "i5">,
|
||||||
<BlogA: id 7, name (CharField) "B4", info (CharField) "i4">,
|
<BlogA: id 7, name (CharField) "B4", info (CharField) "i4">,
|
||||||
<BlogA: id 6, name (CharField) "B3", info (CharField) "i3">,
|
<BlogA: id 6, name (CharField) "B3", info (CharField) "i3">,
|
||||||
|
|
@ -346,7 +478,7 @@ class PolymorphicTests(TestCase):
|
||||||
<BlogB: id 4, name (CharField) "Bb3"> ]'''
|
<BlogB: id 4, name (CharField) "Bb3"> ]'''
|
||||||
|
|
||||||
# PostgreSQL returns this order
|
# PostgreSQL returns this order
|
||||||
expected2='''
|
expected2 = '''
|
||||||
[ <BlogB: id 2, name (CharField) "Bb1">,
|
[ <BlogB: id 2, name (CharField) "Bb1">,
|
||||||
<BlogB: id 3, name (CharField) "Bb2">,
|
<BlogB: id 3, name (CharField) "Bb2">,
|
||||||
<BlogB: id 4, name (CharField) "Bb3">,
|
<BlogB: id 4, name (CharField) "Bb3">,
|
||||||
|
|
@ -359,7 +491,6 @@ class PolymorphicTests(TestCase):
|
||||||
x = '\n' + repr(BlogBase.objects.order_by('-BlogA___info'))
|
x = '\n' + repr(BlogBase.objects.order_by('-BlogA___info'))
|
||||||
self.assertTrue(x == expected1 or x == expected2)
|
self.assertTrue(x == expected1 or x == expected2)
|
||||||
|
|
||||||
|
|
||||||
def test_limit_choices_to(self):
|
def test_limit_choices_to(self):
|
||||||
"""
|
"""
|
||||||
this is not really a testcase, as limit_choices_to only affects the Django admin
|
this is not really a testcase, as limit_choices_to only affects the Django admin
|
||||||
|
|
@ -371,7 +502,6 @@ class PolymorphicTests(TestCase):
|
||||||
entry1 = BlogEntry_limit_choices_to.objects.create(blog=blog_b, text='bla2')
|
entry1 = BlogEntry_limit_choices_to.objects.create(blog=blog_b, text='bla2')
|
||||||
entry2 = BlogEntry_limit_choices_to.objects.create(blog=blog_b, text='bla2')
|
entry2 = BlogEntry_limit_choices_to.objects.create(blog=blog_b, text='bla2')
|
||||||
|
|
||||||
|
|
||||||
def test_primary_key_custom_field_problem(self):
|
def test_primary_key_custom_field_problem(self):
|
||||||
"""
|
"""
|
||||||
object retrieval problem occuring with some custom primary key fields (UUIDField as test case)
|
object retrieval problem occuring with some custom primary key fields (UUIDField as test case)
|
||||||
|
|
@ -389,7 +519,7 @@ class PolymorphicTests(TestCase):
|
||||||
self.assertIsInstance(a.uuid_primary_key, uuid.UUID)
|
self.assertIsInstance(a.uuid_primary_key, uuid.UUID)
|
||||||
self.assertIsInstance(a.pk, uuid.UUID)
|
self.assertIsInstance(a.pk, uuid.UUID)
|
||||||
|
|
||||||
res = re.sub(' "(.*?)..", topic',', topic', repr(qs))
|
res = re.sub(' "(.*?)..", topic', ', topic', repr(qs))
|
||||||
res_exp = """[ <UUIDProject: uuid_primary_key (UUIDField/pk), topic (CharField) "John's gathering">,
|
res_exp = """[ <UUIDProject: uuid_primary_key (UUIDField/pk), topic (CharField) "John's gathering">,
|
||||||
<UUIDArtProject: uuid_primary_key (UUIDField/pk), topic (CharField) "Sculpting with Tim", artist (CharField) "T. Turner">,
|
<UUIDArtProject: uuid_primary_key (UUIDField/pk), topic (CharField) "Sculpting with Tim", artist (CharField) "T. Turner">,
|
||||||
<UUIDResearchProject: uuid_primary_key (UUIDField/pk), topic (CharField) "Swallow Aerodynamics", supervisor (CharField) "Dr. Winter"> ]"""
|
<UUIDResearchProject: uuid_primary_key (UUIDField/pk), topic (CharField) "Swallow Aerodynamics", supervisor (CharField) "Dr. Winter"> ]"""
|
||||||
|
|
@ -413,7 +543,6 @@ class PolymorphicTests(TestCase):
|
||||||
Model2C.objects.create(field1='C1', field2='C2', field3='C3')
|
Model2C.objects.create(field1='C1', field2='C2', field3='C3')
|
||||||
Model2D.objects.create(field1='D1', field2='D2', field3='D3', field4='D4')
|
Model2D.objects.create(field1='D1', field2='D2', field3='D3', field4='D4')
|
||||||
|
|
||||||
|
|
||||||
def test_simple_inheritance(self):
|
def test_simple_inheritance(self):
|
||||||
self.create_model2abcd()
|
self.create_model2abcd()
|
||||||
|
|
||||||
|
|
@ -423,14 +552,12 @@ class PolymorphicTests(TestCase):
|
||||||
self.assertEqual(repr(objects[2]), '<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>')
|
self.assertEqual(repr(objects[2]), '<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>')
|
||||||
self.assertEqual(repr(objects[3]), '<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField)>')
|
self.assertEqual(repr(objects[3]), '<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField)>')
|
||||||
|
|
||||||
|
|
||||||
def test_manual_get_real_instance(self):
|
def test_manual_get_real_instance(self):
|
||||||
self.create_model2abcd()
|
self.create_model2abcd()
|
||||||
|
|
||||||
o = Model2A.objects.non_polymorphic().get(field1='C1')
|
o = Model2A.objects.non_polymorphic().get(field1='C1')
|
||||||
self.assertEqual(repr(o.get_real_instance()), '<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>')
|
self.assertEqual(repr(o.get_real_instance()), '<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>')
|
||||||
|
|
||||||
|
|
||||||
def test_non_polymorphic(self):
|
def test_non_polymorphic(self):
|
||||||
self.create_model2abcd()
|
self.create_model2abcd()
|
||||||
|
|
||||||
|
|
@ -440,7 +567,6 @@ class PolymorphicTests(TestCase):
|
||||||
self.assertEqual(repr(objects[2]), '<Model2A: id 3, field1 (CharField)>')
|
self.assertEqual(repr(objects[2]), '<Model2A: id 3, field1 (CharField)>')
|
||||||
self.assertEqual(repr(objects[3]), '<Model2A: id 4, field1 (CharField)>')
|
self.assertEqual(repr(objects[3]), '<Model2A: id 4, field1 (CharField)>')
|
||||||
|
|
||||||
|
|
||||||
def test_get_real_instances(self):
|
def test_get_real_instances(self):
|
||||||
self.create_model2abcd()
|
self.create_model2abcd()
|
||||||
qs = Model2A.objects.all().non_polymorphic()
|
qs = Model2A.objects.all().non_polymorphic()
|
||||||
|
|
@ -459,7 +585,6 @@ class PolymorphicTests(TestCase):
|
||||||
self.assertEqual(repr(objects[2]), '<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>')
|
self.assertEqual(repr(objects[2]), '<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>')
|
||||||
self.assertEqual(repr(objects[3]), '<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField)>')
|
self.assertEqual(repr(objects[3]), '<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField)>')
|
||||||
|
|
||||||
|
|
||||||
def test_translate_polymorphic_q_object(self):
|
def test_translate_polymorphic_q_object(self):
|
||||||
self.create_model2abcd()
|
self.create_model2abcd()
|
||||||
|
|
||||||
|
|
@ -468,7 +593,6 @@ class PolymorphicTests(TestCase):
|
||||||
self.assertEqual(repr(objects[0]), '<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>')
|
self.assertEqual(repr(objects[0]), '<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>')
|
||||||
self.assertEqual(repr(objects[1]), '<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField)>')
|
self.assertEqual(repr(objects[1]), '<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField)>')
|
||||||
|
|
||||||
|
|
||||||
def test_base_manager(self):
|
def test_base_manager(self):
|
||||||
def show_base_manager(model):
|
def show_base_manager(model):
|
||||||
return "{0} {1}".format(
|
return "{0} {1}".format(
|
||||||
|
|
@ -480,14 +604,13 @@ class PolymorphicTests(TestCase):
|
||||||
self.assertEqual(show_base_manager(PlainB), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.PlainB'>")
|
self.assertEqual(show_base_manager(PlainB), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.PlainB'>")
|
||||||
self.assertEqual(show_base_manager(PlainC), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.PlainC'>")
|
self.assertEqual(show_base_manager(PlainC), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.PlainC'>")
|
||||||
|
|
||||||
self.assertEqual(show_base_manager(Model2A), "<class 'polymorphic.manager.PolymorphicManager'> <class 'polymorphic.tests.Model2A'>")
|
self.assertEqual(show_base_manager(Model2A), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.Model2A'>")
|
||||||
self.assertEqual(show_base_manager(Model2B), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.Model2B'>")
|
self.assertEqual(show_base_manager(Model2B), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.Model2B'>")
|
||||||
self.assertEqual(show_base_manager(Model2C), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.Model2C'>")
|
self.assertEqual(show_base_manager(Model2C), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.Model2C'>")
|
||||||
|
|
||||||
self.assertEqual(show_base_manager(One2OneRelatingModel), "<class 'polymorphic.manager.PolymorphicManager'> <class 'polymorphic.tests.One2OneRelatingModel'>")
|
self.assertEqual(show_base_manager(One2OneRelatingModel), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.One2OneRelatingModel'>")
|
||||||
self.assertEqual(show_base_manager(One2OneRelatingModelDerived), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.One2OneRelatingModelDerived'>")
|
self.assertEqual(show_base_manager(One2OneRelatingModelDerived), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.One2OneRelatingModelDerived'>")
|
||||||
|
|
||||||
|
|
||||||
def test_instance_default_manager(self):
|
def test_instance_default_manager(self):
|
||||||
def show_default_manager(instance):
|
def show_default_manager(instance):
|
||||||
return "{0} {1}".format(
|
return "{0} {1}".format(
|
||||||
|
|
@ -507,9 +630,9 @@ class PolymorphicTests(TestCase):
|
||||||
self.assertEqual(show_default_manager(plain_b), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.PlainB'>")
|
self.assertEqual(show_default_manager(plain_b), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.PlainB'>")
|
||||||
self.assertEqual(show_default_manager(plain_c), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.PlainC'>")
|
self.assertEqual(show_default_manager(plain_c), "<class 'django.db.models.manager.Manager'> <class 'polymorphic.tests.PlainC'>")
|
||||||
|
|
||||||
self.assertEqual(show_default_manager(model_2a), "<class 'polymorphic.manager.PolymorphicManager'> <class 'polymorphic.tests.Model2A'>")
|
self.assertEqual(show_default_manager(model_2a), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.Model2A'>")
|
||||||
self.assertEqual(show_default_manager(model_2b), "<class 'polymorphic.manager.PolymorphicManager'> <class 'polymorphic.tests.Model2B'>")
|
self.assertEqual(show_default_manager(model_2b), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.Model2B'>")
|
||||||
self.assertEqual(show_default_manager(model_2c), "<class 'polymorphic.manager.PolymorphicManager'> <class 'polymorphic.tests.Model2C'>")
|
self.assertEqual(show_default_manager(model_2c), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.Model2C'>")
|
||||||
|
|
||||||
def test_foreignkey_field(self):
|
def test_foreignkey_field(self):
|
||||||
self.create_model2abcd()
|
self.create_model2abcd()
|
||||||
|
|
@ -520,7 +643,6 @@ class PolymorphicTests(TestCase):
|
||||||
object2b = Model2B.base_objects.get(field1='C1')
|
object2b = Model2B.base_objects.get(field1='C1')
|
||||||
self.assertEqual(repr(object2b.model2c), '<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>')
|
self.assertEqual(repr(object2b.model2c), '<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>')
|
||||||
|
|
||||||
|
|
||||||
def test_onetoone_field(self):
|
def test_onetoone_field(self):
|
||||||
self.create_model2abcd()
|
self.create_model2abcd()
|
||||||
|
|
||||||
|
|
@ -534,7 +656,6 @@ class PolymorphicTests(TestCase):
|
||||||
self.assertEqual(repr(c.one2one), '<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>')
|
self.assertEqual(repr(c.one2one), '<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>')
|
||||||
self.assertEqual(repr(a.one2onerelatingmodel), '<One2OneRelatingModelDerived: One2OneRelatingModelDerived object>')
|
self.assertEqual(repr(a.one2onerelatingmodel), '<One2OneRelatingModelDerived: One2OneRelatingModelDerived object>')
|
||||||
|
|
||||||
|
|
||||||
def test_manytomany_field(self):
|
def test_manytomany_field(self):
|
||||||
# Model 1
|
# Model 1
|
||||||
o = ModelShow1.objects.create(field1='abc')
|
o = ModelShow1.objects.create(field1='abc')
|
||||||
|
|
@ -549,7 +670,7 @@ class PolymorphicTests(TestCase):
|
||||||
self.assertEqual(repr(ModelShow2.objects.all()), '[ <ModelShow2: id 1, field1 "abc", m2m 1> ]')
|
self.assertEqual(repr(ModelShow2.objects.all()), '[ <ModelShow2: id 1, field1 "abc", m2m 1> ]')
|
||||||
|
|
||||||
# Model 3
|
# Model 3
|
||||||
o=ModelShow3.objects.create(field1='abc')
|
o = ModelShow3.objects.create(field1='abc')
|
||||||
o.m2m.add(o)
|
o.m2m.add(o)
|
||||||
o.save()
|
o.save()
|
||||||
self.assertEqual(repr(ModelShow3.objects.all()), '[ <ModelShow3: id 1, field1 (CharField) "abc", m2m (ManyToManyField) 1> ]')
|
self.assertEqual(repr(ModelShow3.objects.all()), '[ <ModelShow3: id 1, field1 (CharField) "abc", m2m (ManyToManyField) 1> ]')
|
||||||
|
|
@ -562,7 +683,6 @@ class PolymorphicTests(TestCase):
|
||||||
ModelShow2_plain.objects.create(field1='abc', field2='def')
|
ModelShow2_plain.objects.create(field1='abc', field2='def')
|
||||||
self.assertEqual(repr(ModelShow1_plain.objects.all()), '[<ModelShow1_plain: ModelShow1_plain object>, <ModelShow2_plain: ModelShow2_plain object>]')
|
self.assertEqual(repr(ModelShow1_plain.objects.all()), '[<ModelShow1_plain: ModelShow1_plain object>, <ModelShow2_plain: ModelShow2_plain object>]')
|
||||||
|
|
||||||
|
|
||||||
def test_extra_method(self):
|
def test_extra_method(self):
|
||||||
self.create_model2abcd()
|
self.create_model2abcd()
|
||||||
|
|
||||||
|
|
@ -581,7 +701,7 @@ class PolymorphicTests(TestCase):
|
||||||
ModelExtraExternal.objects.create(topic='extra1')
|
ModelExtraExternal.objects.create(topic='extra1')
|
||||||
ModelExtraExternal.objects.create(topic='extra2')
|
ModelExtraExternal.objects.create(topic='extra2')
|
||||||
ModelExtraExternal.objects.create(topic='extra3')
|
ModelExtraExternal.objects.create(topic='extra3')
|
||||||
objects = ModelExtraA.objects.extra(tables=["polymorphic_modelextraexternal"], select={"topic":"polymorphic_modelextraexternal.topic"}, where=["polymorphic_modelextraa.id = polymorphic_modelextraexternal.id"])
|
objects = ModelExtraA.objects.extra(tables=["polymorphic_modelextraexternal"], select={"topic": "polymorphic_modelextraexternal.topic"}, where=["polymorphic_modelextraa.id = polymorphic_modelextraexternal.id"])
|
||||||
if six.PY3:
|
if six.PY3:
|
||||||
self.assertEqual(repr(objects[0]), '<ModelExtraA: id 1, field1 (CharField) "A1" - Extra: topic (str) "extra1">')
|
self.assertEqual(repr(objects[0]), '<ModelExtraA: id 1, field1 (CharField) "A1" - Extra: topic (str) "extra1">')
|
||||||
self.assertEqual(repr(objects[1]), '<ModelExtraB: id 2, field1 (CharField) "B1", field2 (CharField) "B2" - Extra: topic (str) "extra2">')
|
self.assertEqual(repr(objects[1]), '<ModelExtraB: id 2, field1 (CharField) "B1", field2 (CharField) "B2" - Extra: topic (str) "extra2">')
|
||||||
|
|
@ -592,7 +712,6 @@ class PolymorphicTests(TestCase):
|
||||||
self.assertEqual(repr(objects[2]), '<ModelExtraC: id 3, field1 (CharField) "C1", field2 (CharField) "C2", field3 (CharField) "C3" - Extra: topic (unicode) "extra3">')
|
self.assertEqual(repr(objects[2]), '<ModelExtraC: id 3, field1 (CharField) "C1", field2 (CharField) "C2", field3 (CharField) "C3" - Extra: topic (unicode) "extra3">')
|
||||||
self.assertEqual(len(objects), 3)
|
self.assertEqual(len(objects), 3)
|
||||||
|
|
||||||
|
|
||||||
def test_instance_of_filter(self):
|
def test_instance_of_filter(self):
|
||||||
self.create_model2abcd()
|
self.create_model2abcd()
|
||||||
|
|
||||||
|
|
@ -618,15 +737,29 @@ class PolymorphicTests(TestCase):
|
||||||
self.assertEqual(repr(objects[0]), '<Model2A: id 1, field1 (CharField)>')
|
self.assertEqual(repr(objects[0]), '<Model2A: id 1, field1 (CharField)>')
|
||||||
self.assertEqual(len(objects), 1)
|
self.assertEqual(len(objects), 1)
|
||||||
|
|
||||||
|
|
||||||
def test_polymorphic___filter(self):
|
def test_polymorphic___filter(self):
|
||||||
self.create_model2abcd()
|
self.create_model2abcd()
|
||||||
|
|
||||||
objects = Model2A.objects.filter(Q( Model2B___field2='B2') | Q( Model2C___field3='C3'))
|
objects = Model2A.objects.filter(Q(Model2B___field2='B2') | Q(Model2C___field3='C3'))
|
||||||
self.assertEqual(len(objects), 2)
|
self.assertEqual(len(objects), 2)
|
||||||
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)>')
|
||||||
|
|
||||||
|
def test_polymorphic___filter_field(self):
|
||||||
|
p = ModelUnderRelParent.objects.create(_private=True, field1='AA')
|
||||||
|
ModelUnderRelChild.objects.create(parent=p, _private2=True)
|
||||||
|
|
||||||
|
# The "___" filter should also parse to "parent" -> "_private" as fallback.
|
||||||
|
objects = ModelUnderRelChild.objects.filter(parent___private=True)
|
||||||
|
self.assertEqual(len(objects), 1)
|
||||||
|
|
||||||
|
def test_polymorphic___filter_reverse_field(self):
|
||||||
|
p = ModelUnderRelParent.objects.create(_private=True, field1='BB')
|
||||||
|
ModelUnderRelChild.objects.create(parent=p, _private2=True)
|
||||||
|
|
||||||
|
# Also test for reverse relations
|
||||||
|
objects = ModelUnderRelParent.objects.filter(children___private2=True)
|
||||||
|
self.assertEqual(len(objects), 1)
|
||||||
|
|
||||||
def test_delete(self):
|
def test_delete(self):
|
||||||
self.create_model2abcd()
|
self.create_model2abcd()
|
||||||
|
|
@ -642,7 +775,6 @@ class PolymorphicTests(TestCase):
|
||||||
self.assertEqual(repr(objects[2]), '<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField)>')
|
self.assertEqual(repr(objects[2]), '<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField)>')
|
||||||
self.assertEqual(len(objects), 3)
|
self.assertEqual(len(objects), 3)
|
||||||
|
|
||||||
|
|
||||||
def test_combine_querysets(self):
|
def test_combine_querysets(self):
|
||||||
ModelX.objects.create(field_x='x')
|
ModelX.objects.create(field_x='x')
|
||||||
ModelY.objects.create(field_y='y')
|
ModelY.objects.create(field_y='y')
|
||||||
|
|
@ -652,7 +784,6 @@ class PolymorphicTests(TestCase):
|
||||||
self.assertEqual(repr(qs[1]), '<ModelY: id 2, field_b (CharField), field_y (CharField)>')
|
self.assertEqual(repr(qs[1]), '<ModelY: id 2, field_b (CharField), field_y (CharField)>')
|
||||||
self.assertEqual(len(qs), 2)
|
self.assertEqual(len(qs), 2)
|
||||||
|
|
||||||
|
|
||||||
def test_multiple_inheritance(self):
|
def test_multiple_inheritance(self):
|
||||||
# multiple inheritance, subclassing third party models (mix PolymorphicModel with models.Model)
|
# multiple inheritance, subclassing third party models (mix PolymorphicModel with models.Model)
|
||||||
|
|
||||||
|
|
@ -697,7 +828,6 @@ class PolymorphicTests(TestCase):
|
||||||
self.assertEqual(repr(objects[1]), '<RelationB: id 3, field_base (CharField) "B1", fk (ForeignKey) RelationA, field_b (CharField) "B2", m2m (ManyToManyField) 1>')
|
self.assertEqual(repr(objects[1]), '<RelationB: id 3, field_base (CharField) "B1", fk (ForeignKey) RelationA, field_b (CharField) "B2", m2m (ManyToManyField) 1>')
|
||||||
self.assertEqual(len(objects), 2)
|
self.assertEqual(len(objects), 2)
|
||||||
|
|
||||||
|
|
||||||
def test_user_defined_manager(self):
|
def test_user_defined_manager(self):
|
||||||
self.create_model2abcd()
|
self.create_model2abcd()
|
||||||
ModelWithMyManager.objects.create(field1='D1a', field4='D4a')
|
ModelWithMyManager.objects.create(field1='D1a', field4='D4a')
|
||||||
|
|
@ -737,7 +867,7 @@ 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+")
|
@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')
|
||||||
|
|
@ -752,7 +882,6 @@ class PolymorphicTests(TestCase):
|
||||||
self.assertEqual(type(ModelWithMyManager2._default_manager).__name__, 'PolymorphicManagerFromMyManagerQuerySet')
|
self.assertEqual(type(ModelWithMyManager2._default_manager).__name__, 'PolymorphicManagerFromMyManagerQuerySet')
|
||||||
self.assertIs(type(ModelWithMyManager2.base_objects), models.Manager)
|
self.assertIs(type(ModelWithMyManager2.base_objects), models.Manager)
|
||||||
|
|
||||||
|
|
||||||
def test_manager_inheritance(self):
|
def test_manager_inheritance(self):
|
||||||
# by choice of MRO, should be MyManager from MROBase1.
|
# by choice of MRO, should be MyManager from MROBase1.
|
||||||
self.assertIs(type(MRODerived.objects), MyManager)
|
self.assertIs(type(MRODerived.objects), MyManager)
|
||||||
|
|
@ -763,7 +892,6 @@ class PolymorphicTests(TestCase):
|
||||||
# Django vanilla inheritance does not inherit MyManager as _default_manager here
|
# Django vanilla inheritance does not inherit MyManager as _default_manager here
|
||||||
self.assertIs(type(MROBase2._default_manager), MyManager)
|
self.assertIs(type(MROBase2._default_manager), MyManager)
|
||||||
|
|
||||||
|
|
||||||
def test_queryset_assignment(self):
|
def test_queryset_assignment(self):
|
||||||
# This is just a consistency check for now, testing standard Django behavior.
|
# This is just a consistency check for now, testing standard Django behavior.
|
||||||
parent = PlainParentModelWithManager.objects.create()
|
parent = PlainParentModelWithManager.objects.create()
|
||||||
|
|
@ -787,7 +915,6 @@ class PolymorphicTests(TestCase):
|
||||||
# A related set is created using the model's _default_manager, so does gain extra methods.
|
# A related set is created using the model's _default_manager, so does gain extra methods.
|
||||||
self.assertIs(type(parent.childmodel_set.my_queryset_foo()), MyManagerQuerySet)
|
self.assertIs(type(parent.childmodel_set.my_queryset_foo()), MyManagerQuerySet)
|
||||||
|
|
||||||
|
|
||||||
def test_proxy_models(self):
|
def test_proxy_models(self):
|
||||||
# prepare some data
|
# prepare some data
|
||||||
for data in ('bleep bloop', 'I am a', 'computer'):
|
for data in ('bleep bloop', 'I am a', 'computer'):
|
||||||
|
|
@ -808,7 +935,7 @@ class PolymorphicTests(TestCase):
|
||||||
This unit test guards that this check is working properly. For instance,
|
This unit test guards that this check is working properly. For instance,
|
||||||
proxy child models need to be handled separately.
|
proxy child models need to be handled separately.
|
||||||
"""
|
"""
|
||||||
name="Item1"
|
name = "Item1"
|
||||||
nonproxychild = NonProxyChild.objects.create(name=name)
|
nonproxychild = NonProxyChild.objects.create(name=name)
|
||||||
|
|
||||||
pb = ProxyBase.objects.get(id=1)
|
pb = ProxyBase.objects.get(id=1)
|
||||||
|
|
@ -829,7 +956,6 @@ class PolymorphicTests(TestCase):
|
||||||
ct = ContentType.objects.get_for_model(ProxyChild, for_concrete_model=False)
|
ct = ContentType.objects.get_for_model(ProxyChild, for_concrete_model=False)
|
||||||
self.assertEqual(ProxyChild, ct.model_class())
|
self.assertEqual(ProxyChild, ct.model_class())
|
||||||
|
|
||||||
|
|
||||||
def test_proxy_model_inheritance(self):
|
def test_proxy_model_inheritance(self):
|
||||||
"""
|
"""
|
||||||
Polymorphic abilities should also work when the base model is a proxy object.
|
Polymorphic abilities should also work when the base model is a proxy object.
|
||||||
|
|
@ -869,7 +995,7 @@ class PolymorphicTests(TestCase):
|
||||||
self.assertEqual(repr(qs[1]), '<CustomPkInherit: id 2, b (CharField) "b", custom_id (AutoField/pk) 1, i (CharField) "i">')
|
self.assertEqual(repr(qs[1]), '<CustomPkInherit: id 2, b (CharField) "b", custom_id (AutoField/pk) 1, i (CharField) "i">')
|
||||||
|
|
||||||
def test_fix_getattribute(self):
|
def test_fix_getattribute(self):
|
||||||
### fixed issue in PolymorphicModel.__getattribute__: field name same as model name
|
# fixed issue in PolymorphicModel.__getattribute__: field name same as model name
|
||||||
o = ModelFieldNameTest.objects.create(modelfieldnametest='1')
|
o = ModelFieldNameTest.objects.create(modelfieldnametest='1')
|
||||||
self.assertEqual(repr(o), '<ModelFieldNameTest: id 1, modelfieldnametest (CharField)>')
|
self.assertEqual(repr(o), '<ModelFieldNameTest: id 1, modelfieldnametest (CharField)>')
|
||||||
|
|
||||||
|
|
@ -883,21 +1009,20 @@ class PolymorphicTests(TestCase):
|
||||||
t.save()
|
t.save()
|
||||||
p = ModelShow1_plain.objects.get(field1="TestParentLinkAndRelatedName")
|
p = ModelShow1_plain.objects.get(field1="TestParentLinkAndRelatedName")
|
||||||
|
|
||||||
#check that p is equal to the
|
# check that p is equal to the
|
||||||
self.assertIsInstance(p, TestParentLinkAndRelatedName)
|
self.assertIsInstance(p, TestParentLinkAndRelatedName)
|
||||||
self.assertEqual(p, t)
|
self.assertEqual(p, t)
|
||||||
|
|
||||||
#check that the accessors to parent and sublass work correctly and return the right object
|
# check that the accessors to parent and sublass work correctly and return the right object
|
||||||
p = ModelShow1_plain.objects.non_polymorphic().get(field1="TestParentLinkAndRelatedName")
|
p = ModelShow1_plain.objects.non_polymorphic().get(field1="TestParentLinkAndRelatedName")
|
||||||
self.assertNotEqual(p, t) #p should be Plain1 and t TestParentLinkAndRelatedName, so not equal
|
self.assertNotEqual(p, t) # p should be Plain1 and t TestParentLinkAndRelatedName, so not equal
|
||||||
self.assertEqual(p, t.superclass)
|
self.assertEqual(p, t.superclass)
|
||||||
self.assertEqual(p.related_name_subclass, t)
|
self.assertEqual(p.related_name_subclass, t)
|
||||||
|
|
||||||
#test that we can delete the object
|
# test that we can delete the object
|
||||||
t.delete()
|
t.delete()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class RegressionTests(TestCase):
|
class RegressionTests(TestCase):
|
||||||
|
|
||||||
def test_for_query_result_incomplete_with_inheritance(self):
|
def test_for_query_result_incomplete_with_inheritance(self):
|
||||||
|
|
@ -918,4 +1043,3 @@ class RegressionTests(TestCase):
|
||||||
|
|
||||||
expected_queryset = [bottom]
|
expected_queryset = [bottom]
|
||||||
self.assertQuerysetEqual(Bottom.objects.all(), [repr(r) for r in expected_queryset])
|
self.assertQuerysetEqual(Bottom.objects.all(), [repr(r) for r in expected_queryset])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ class UUIDField(six.with_metaclass(models.SubfieldBase, models.CharField)):
|
||||||
self.namespace, self.name = namespace, name
|
self.namespace, self.name = namespace, name
|
||||||
|
|
||||||
super(UUIDField, self).__init__(verbose_name=verbose_name,
|
super(UUIDField, self).__init__(verbose_name=verbose_name,
|
||||||
name=name, **kwargs)
|
name=name, **kwargs)
|
||||||
|
|
||||||
def create_uuid(self):
|
def create_uuid(self):
|
||||||
if not self.version or self.version == 4:
|
if not self.version or self.version == 4:
|
||||||
|
|
@ -103,11 +103,11 @@ class UUIDField(six.with_metaclass(models.SubfieldBase, models.CharField)):
|
||||||
# instance), everything works.
|
# instance), everything works.
|
||||||
#
|
#
|
||||||
|
|
||||||
#if not value:
|
# if not value:
|
||||||
# return None
|
# return None
|
||||||
#if isinstance(value, uuid.UUID):
|
# if isinstance(value, uuid.UUID):
|
||||||
# return smart_text(value)
|
# return smart_text(value)
|
||||||
#else:
|
# else:
|
||||||
# return value
|
# return value
|
||||||
|
|
||||||
def pre_save(self, model_instance, add):
|
def pre_save(self, model_instance, add):
|
||||||
|
|
@ -139,6 +139,6 @@ class UUIDField(six.with_metaclass(models.SubfieldBase, models.CharField)):
|
||||||
defaults = {
|
defaults = {
|
||||||
'form_class': forms.CharField,
|
'form_class': forms.CharField,
|
||||||
'max_length': self.max_length
|
'max_length': self.max_length
|
||||||
}
|
}
|
||||||
defaults.update(kwargs)
|
defaults.update(kwargs)
|
||||||
return super(UUIDField, self).formfield(**defaults)
|
return super(UUIDField, self).formfield(**defaults)
|
||||||
|
|
|
||||||
18
runtests.py
18
runtests.py
|
|
@ -19,15 +19,15 @@ sys.stderr.write('Using Django version {0} from {1}\n'.format(
|
||||||
|
|
||||||
if not settings.configured:
|
if not settings.configured:
|
||||||
settings.configure(
|
settings.configure(
|
||||||
DEBUG = True,
|
DEBUG=True,
|
||||||
TEMPLATE_DEBUG = True,
|
TEMPLATE_DEBUG=True,
|
||||||
DATABASES = {
|
DATABASES={
|
||||||
'default': {
|
'default': {
|
||||||
'ENGINE': 'django.db.backends.sqlite3',
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
'NAME': ':memory:'
|
'NAME': ':memory:'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
TEMPLATE_LOADERS = (
|
TEMPLATE_LOADERS=(
|
||||||
'django.template.loaders.app_directories.Loader',
|
'django.template.loaders.app_directories.Loader',
|
||||||
),
|
),
|
||||||
TEMPLATE_CONTEXT_PROCESSORS=(
|
TEMPLATE_CONTEXT_PROCESSORS=(
|
||||||
|
|
@ -37,7 +37,7 @@ if not settings.configured:
|
||||||
'django.core.context_processors.request',
|
'django.core.context_processors.request',
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
TEST_RUNNER = 'django.test.runner.DiscoverRunner' if django.VERSION >= (1,7) else 'django.test.simple.DjangoTestSuiteRunner',
|
TEST_RUNNER = 'django.test.runner.DiscoverRunner' if django.VERSION >= (1, 7) else 'django.test.simple.DjangoTestSuiteRunner',
|
||||||
INSTALLED_APPS = (
|
INSTALLED_APPS = (
|
||||||
'django.contrib.auth',
|
'django.contrib.auth',
|
||||||
'django.contrib.contenttypes',
|
'django.contrib.contenttypes',
|
||||||
|
|
@ -50,9 +50,15 @@ if not settings.configured:
|
||||||
SITE_ID = 3,
|
SITE_ID = 3,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
DEFAULT_TEST_APPS = [
|
||||||
|
'polymorphic',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def runtests():
|
def runtests():
|
||||||
argv = sys.argv[:1] + ['test', 'polymorphic', '--traceback'] + sys.argv[1:]
|
other_args = list(filter(lambda arg: arg.startswith('-'), sys.argv[1:]))
|
||||||
|
test_apps = list(filter(lambda arg: not arg.startswith('-'), sys.argv[1:])) or DEFAULT_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__':
|
||||||
|
|
|
||||||
24
setup.py
24
setup.py
|
|
@ -21,22 +21,22 @@ def find_version(*parts):
|
||||||
|
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name = 'django_polymorphic',
|
name='django_polymorphic',
|
||||||
version = find_version('polymorphic', '__version__.py'),
|
version=find_version('polymorphic', '__init__.py'),
|
||||||
license = 'BSD',
|
license='BSD',
|
||||||
|
|
||||||
description = 'Seamless Polymorphic Inheritance for Django Models',
|
description='Seamless Polymorphic Inheritance for Django Models',
|
||||||
long_description = read('README.rst'),
|
long_description=read('README.rst'),
|
||||||
url = 'https://github.com/chrisglass/django_polymorphic',
|
url='https://github.com/chrisglass/django_polymorphic',
|
||||||
|
|
||||||
author = 'Bert Constantin',
|
author='Bert Constantin',
|
||||||
author_email = 'bert.constantin@gmx.de',
|
author_email='bert.constantin@gmx.de',
|
||||||
|
|
||||||
maintainer = 'Christopher Glass',
|
maintainer='Christopher Glass',
|
||||||
maintainer_email = 'tribaal@gmail.com',
|
maintainer_email='tribaal@gmail.com',
|
||||||
|
|
||||||
packages = find_packages(),
|
packages=find_packages(),
|
||||||
package_data = {
|
package_data={
|
||||||
'polymorphic': [
|
'polymorphic': [
|
||||||
'templates/admin/polymorphic/*.html',
|
'templates/admin/polymorphic/*.html',
|
||||||
],
|
],
|
||||||
|
|
|
||||||
4
tox.ini
4
tox.ini
|
|
@ -22,6 +22,6 @@ commands=
|
||||||
python runtests.py
|
python runtests.py
|
||||||
|
|
||||||
[testenv:docs]
|
[testenv:docs]
|
||||||
changedir=docs
|
|
||||||
deps=Sphinx
|
deps=Sphinx
|
||||||
commands=sphinx-build -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html
|
changedir = docs
|
||||||
|
commands = sphinx-build -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue