Merge remote-tracking branch 'upstream/master' into allow_extra_manager

fix_request_path_info
gilgamezh 2015-12-29 17:49:09 -03:00
commit b17aa58ad9
26 changed files with 567 additions and 335 deletions

View File

@ -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
:class:`~polymorphic.showfields.ShowFieldType` class mixin::
from polymorphic import PolymorphicModel, ShowFieldType
from polymorphic.showfields import PolymorphicModel, ShowFieldType
class ModelA(ShowFieldType, PolymorphicModel):
field1 = models.CharField(max_length=10)

View File

@ -1,6 +1,42 @@
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)
--------------------------

View File

@ -11,7 +11,8 @@
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
import sys
import os
# 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
@ -54,9 +55,9 @@ copyright = u'2013, Bert Constantin, Chris Glass, Diederik van der Boor'
# built documents.
#
# The short X.Y version.
version = '0.7.2'
version = '0.8.1'
# 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
# for a list of supported languages.
@ -176,21 +177,21 @@ htmlhelp_basename = 'django-polymorphicdoc'
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'django-polymorphic.tex', u'django-polymorphic Documentation',
u'Bert Constantin, Chris Glass, Diederik van der Boor', 'manual'),
('index', 'django-polymorphic.tex', u'django-polymorphic Documentation',
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
@ -233,9 +234,9 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'django-polymorphic', u'django-polymorphic Documentation',
u'Bert Constantin, Chris Glass, Diederik van der Boor', 'django-polymorphic', 'One line description of project.',
'Miscellaneous'),
('index', 'django-polymorphic', u'django-polymorphic Documentation',
u'Bert Constantin, Chris Glass, Diederik van der Boor', 'django-polymorphic', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.

View File

@ -75,7 +75,7 @@ INSTALLED_APPS = (
'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
# Logging configuration

View File

@ -14,6 +14,7 @@ class ProjectChildAdmin(PolymorphicChildModelAdmin):
}),
)
class ProjectAdmin(PolymorphicParentModelAdmin):
base_model = Project
list_filter = (PolymorphicChildModelFilter,)
@ -26,10 +27,10 @@ class ProjectAdmin(PolymorphicParentModelAdmin):
admin.site.register(Project, ProjectAdmin)
class ModelAChildAdmin(PolymorphicChildModelAdmin):
base_model = ModelA
class ModelAAdmin(PolymorphicParentModelAdmin):
base_model = ModelA
list_filter = (PolymorphicChildModelFilter,)
@ -45,6 +46,7 @@ admin.site.register(ModelA, ModelAAdmin)
class Model2AChildAdmin(PolymorphicChildModelAdmin):
base_model = Model2A
class Model2AAdmin(PolymorphicParentModelAdmin):
base_model = Model2A
list_filter = (PolymorphicChildModelFilter,)
@ -60,6 +62,7 @@ admin.site.register(Model2A, Model2AAdmin)
class UUIDModelAChildAdmin(PolymorphicChildModelAdmin):
base_model = UUIDModelA
class UUIDModelAAdmin(PolymorphicParentModelAdmin):
base_model = UUIDModelA
list_filter = (PolymorphicChildModelFilter,)
@ -75,6 +78,7 @@ admin.site.register(UUIDModelA, UUIDModelAAdmin)
class ProxyChildAdmin(PolymorphicChildModelAdmin):
base_model = ProxyBase
class ProxyAdmin(PolymorphicParentModelAdmin):
base_model = ProxyBase
list_filter = (PolymorphicChildModelFilter,)

View File

@ -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.
"""
import uuid
import django
from django.core.management.base import NoArgsCommand
from django.db.models import connection
from django.db import connection
from pprint import pprint
import time,sys
import time
import sys
from pexp.models import *
def reset_queries():
connection.queries=[]
if django.VERSION < (1, 9):
connection.queries = []
else:
connection.queries_log.clear()
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 wrapper(*arg):
results=[]
results = []
reset_queries()
for i in xrange(iterations):
t1 = time.time()
x = func(*arg)
t2 = time.time()
results.append((t2-t1)*1000.0)
res_sum=0
for r in results: res_sum +=r
results.append((t2 - t1) * 1000.0)
res_sum = 0
for r in results:
res_sum += r
median = res_sum / len(results)
print '%s%-19s: %.4f ms, %i queries (%i times)' % (
message,func.func_name,
message, func.func_name,
res_sum,
len(connection.queries),
iterations
)
)
sys.stdout.flush()
return wrapper
class Command(NoArgsCommand):
help = ""
def handle_noargs(self, **options):
if False:
ModelA.objects.all().delete()
a=ModelA.objects.create(field1='A1')
b=ModelB.objects.create(field1='B1', field2='B2')
c=ModelC.objects.create(field1='C1', field2='C2', field3='C3')
a = ModelA.objects.create(field1='A1')
b = ModelB.objects.create(field1='B1', field2='B2')
c = ModelC.objects.create(field1='C1', field2='C2', field3='C3')
reset_queries()
print ModelC.base_objects.all();
print ModelC.base_objects.all()
show_queries()
if False:
ModelA.objects.all().delete()
for i in xrange(1000):
a=ModelA.objects.create(field1=str(i%100))
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))
if i%100==0: print i
a = ModelA.objects.create(field1=str(i % 100))
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))
if i % 100 == 0:
print i
f=print_timing(poly_sql_query,iterations=1000)
f = print_timing(poly_sql_query, iterations=1000)
f()
f=print_timing(poly_sql_query2,iterations=1000)
f = print_timing(poly_sql_query2, iterations=1000)
f()
return
nModelA.objects.all().delete()
a=nModelA.objects.create(field1='A1')
b=nModelB.objects.create(field1='B1', field2='B2')
c=nModelC.objects.create(field1='C1', field2='C2', field3='C3')
qs=ModelA.objects.raw("SELECT * from pexp_modela")
for o in list(qs): print o
a = nModelA.objects.create(field1='A1')
b = nModelB.objects.create(field1='B1', field2='B2')
c = nModelC.objects.create(field1='C1', field2='C2', field3='C3')
qs = ModelA.objects.raw("SELECT * from pexp_modela")
for o in list(qs):
print o
from django.db import connection, transaction
from random import Random
rnd=Random()
rnd = Random()
def poly_sql_query():
cursor = connection.cursor()
@ -90,10 +107,11 @@ def poly_sql_query():
ON pexp_modelb.modela_ptr_id = pexp_modelc.modelb_ptr_id
WHERE pexp_modela.field1=%i
ORDER BY pexp_modela.id
""" % rnd.randint(0,100) )
#row=cursor.fetchone()
""" % rnd.randint(0, 100) )
# row=cursor.fetchone()
return
def poly_sql_query2():
cursor = connection.cursor()
cursor.execute("""
@ -101,6 +119,6 @@ def poly_sql_query2():
FROM pexp_modela
WHERE pexp_modela.field1=%i
ORDER BY pexp_modela.id
""" % rnd.randint(0,100) )
#row=cursor.fetchone()
""" % rnd.randint(0, 100) )
# row=cursor.fetchone()
return

View File

@ -4,32 +4,38 @@ This module is a scratchpad for general development, testing & debugging.
"""
from django.core.management.base import NoArgsCommand
from django.db.models import connection
from django.db import connection
from pprint import pprint
from pexp.models import *
def reset_queries():
connection.queries=[]
connection.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):
help = ""
def handle_noargs(self, **options):
Project.objects.all().delete()
a=Project.objects.create(topic="John's gathering")
b=ArtProject.objects.create(topic="Sculpting with Tim", artist="T. Turner")
c=ResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter")
a = Project.objects.create(topic="John's gathering")
b = ArtProject.objects.create(topic="Sculpting with Tim", artist="T. Turner")
c = ResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter")
print Project.objects.all()
print
ModelA.objects.all().delete()
a=ModelA.objects.create(field1='A1')
b=ModelB.objects.create(field1='B1', field2='B2')
c=ModelC.objects.create(field1='C1', field2='C2', field3='C3')
a = ModelA.objects.create(field1='A1')
b = ModelB.objects.create(field1='B1', field2='B2')
c = ModelC.objects.create(field1='C1', field2='C2', field3='C3')
print ModelA.objects.all()
print

View File

@ -3,101 +3,120 @@
This module is a scratchpad for general development, testing & debugging
"""
import django
from django.core.management.base import NoArgsCommand
from django.db.models import connection
from django.db import connection
from pprint import pprint
import sys
from pexp.models import *
num_objects=1000
num_objects = 1000
def reset_queries():
connection.queries=[]
if django.VERSION < (1, 9):
connection.queries = []
else:
connection.queries_log.clear()
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
###################################################################################
### benchmark wrappers
# benchmark wrappers
def print_timing(func, message='', iterations=1):
def wrapper(*arg):
results=[]
results = []
reset_queries()
for i in xrange(iterations):
t1 = time.time()
x = func(*arg)
t2 = time.time()
results.append((t2-t1)*1000.0)
res_sum=0
for r in results: res_sum +=r
results.append((t2 - t1) * 1000.0)
res_sum = 0
for r in results:
res_sum += r
median = res_sum / len(results)
print '%s%-19s: %.0f ms, %i queries' % (
message,func.func_name,
message, func.func_name,
median,
len(connection.queries)/len(results)
)
len(connection.queries) / len(results)
)
sys.stdout.flush()
return wrapper
def run_vanilla_any_poly(func, iterations=1):
f=print_timing(func,' ', iterations)
f = print_timing(func, ' ', iterations)
f(nModelC)
f=print_timing(func,'poly ', iterations)
f = print_timing(func, 'poly ', iterations)
f(ModelC)
###################################################################################
### benchmarks
# benchmarks
def bench_create(model):
for i in xrange(num_objects):
model.objects.create(field1='abc'+str(i), field2='abcd'+str(i), field3='abcde'+str(i))
#print 'count:',model.objects.count()
model.objects.create(field1='abc' + str(i), field2='abcd' + str(i), field3='abcde' + str(i))
# print 'count:',model.objects.count()
def bench_load1(model):
for o in model.objects.all():
pass
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]:
pass
def bench_load2(model):
for o in model.objects.all():
f1=o.field1
f2=o.field2
f3=o.field3
f1 = o.field1
f2 = o.field2
f3 = o.field3
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]:
f1=o.field1
f2=o.field2
f3=o.field3
f1 = o.field1
f2 = o.field2
f3 = o.field3
def bench_delete(model):
model.objects.all().delete()
###################################################################################
### Command
# Command
class Command(NoArgsCommand):
help = ""
def handle_noargs(self, **options):
func_list = [
( bench_delete, 1 ),
( bench_create, 1 ),
( bench_load1, 5 ),
( bench_load1_short, 5 ),
( bench_load2, 5 ),
( bench_load2_short, 5 )
]
for f,iterations in func_list:
run_vanilla_any_poly(f,iterations=iterations)
(bench_delete, 1),
(bench_create, 1),
(bench_load1, 5),
(bench_load1_short, 5),
(bench_load2, 5),
(bench_load2_short, 5)
]
for f, iterations in func_list:
run_vanilla_any_poly(f, iterations=iterations)
print

View File

@ -4,27 +4,31 @@ This module is a scratchpad for general development, testing & debugging
"""
from django.core.management.base import NoArgsCommand
from django.db.models import connection
from django.db import connection
from pprint import pprint
from pexp.models import *
def reset_queries():
connection.queries=[]
connection.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):
help = ""
def handle_noargs(self, **options):
Project.objects.all().delete()
o=Project.objects.create(topic="John's gathering")
o=ArtProject.objects.create(topic="Sculpting with Tim", artist="T. Turner")
o=ResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter")
o = Project.objects.create(topic="John's gathering")
o = ArtProject.objects.create(topic="Sculpting with Tim", artist="T. Turner")
o = ResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter")
print Project.objects.all()
print

View File

@ -6,48 +6,74 @@ from django.db import models
from polymorphic.models import PolymorphicModel
from polymorphic.showfields import ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent
class Project(ShowFieldContent, PolymorphicModel):
topic = models.CharField(max_length=30)
class ArtProject(Project):
artist = models.CharField(max_length=30)
class ResearchProject(Project):
supervisor = models.CharField(max_length=30)
class ModelA(ShowFieldTypeAndContent, PolymorphicModel):
field1 = models.CharField(max_length=10)
class ModelB(ModelA):
field2 = models.CharField(max_length=10)
class ModelC(ModelB):
field3 = models.CharField(max_length=10)
field4 = models.ManyToManyField(ModelB, related_name='related_c')
class nModelA(models.Model):
field1 = models.CharField(max_length=10)
class nModelB(nModelA):
field2 = models.CharField(max_length=10)
class nModelC(nModelB):
field3 = models.CharField(max_length=10)
class Model2A(PolymorphicModel):
field1 = models.CharField(max_length=10)
class Model2B(Model2A):
field2 = models.CharField(max_length=10)
class Model2C(Model2B):
field3 = models.CharField(max_length=10)
if django.VERSION < (1,8):
if django.VERSION < (1, 8):
from polymorphic.tools_for_tests import UUIDField
else:
from django.db.models import UUIDField
class UUIDModelA(ShowFieldTypeAndContent, PolymorphicModel):
uuid_primary_key = UUIDField(primary_key = True)
uuid_primary_key = UUIDField(primary_key=True)
field1 = models.CharField(max_length=10)
class UUIDModelB(UUIDModelA):
field2 = models.CharField(max_length=10)
class UUIDModelC(UUIDModelB):
field3 = models.CharField(max_length=10)
class ProxyBase(PolymorphicModel):
title = models.CharField(max_length=200)
@ -57,14 +83,18 @@ class ProxyBase(PolymorphicModel):
class Meta:
ordering = ('title',)
class ProxyA(ProxyBase):
class Meta:
proxy = True
def __unicode__(self):
return u"<ProxyA: {0}>".format(self.title)
class ProxyB(ProxyBase):
class Meta:
proxy = True

View File

@ -6,13 +6,12 @@ Copyright:
This code and affiliated files are (C) by Bert Constantin and individual contributors.
Please see LICENSE and AUTHORS for more information.
"""
from __future__ import absolute_import
import django
from .showfields import ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent
from .showfields import ShowFields, ShowFieldTypes, ShowFieldsAndTypes # import old names for compatibility
# See PEP 440 (https://www.python.org/dev/peps/pep-0440/)
__version__ = "0.8.1"
# Monkey-patch Django < 1.5 to allow ContentTypes for proxy models.
import django
if django.VERSION[:2] < (1, 5):
from django.contrib.contenttypes.models import ContentTypeManager
from django.utils.encoding import smart_text
@ -29,9 +28,9 @@ if django.VERSION[:2] < (1, 5):
ct = self._get_from_cache(opts)
except KeyError:
ct, created = self.get_or_create(
app_label = opts.app_label,
model = opts.object_name.lower(),
defaults = {'name': smart_text(opts.verbose_name_raw)},
app_label=opts.app_label,
model=opts.object_name.lower(),
defaults={'name': smart_text(opts.verbose_name_raw)},
)
self._add_to_cache(self.db, ct)
@ -39,4 +38,3 @@ if django.VERSION[:2] < (1, 5):
ContentTypeManager.get_for_model__original = ContentTypeManager.get_for_model
ContentTypeManager.get_for_model = get_for_model

View File

@ -1,5 +0,0 @@
# -*- coding: utf-8 -*-
"""
See PEP 440 (https://www.python.org/dev/peps/pep-0440/)
"""
__version__ = "0.7.2"

View File

@ -42,6 +42,7 @@ class RegistrationClosed(RuntimeError):
"The admin model can't be registered anymore at this point."
pass
class ChildAdminNotRegistered(RuntimeError):
"The admin site for the model is not registered."
pass
@ -122,13 +123,11 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
#: If your primary key consists of string values, update this regular expression.
pk_regex = '(\d+|__fk__)'
def __init__(self, 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._is_setup = False
def _lazy_setup(self):
if self._is_setup:
return
@ -150,7 +149,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
self._child_admin_site._registry = complete_registry
self._is_setup = True
def register_child(self, model, model_admin):
"""
Register a model with admin to display.
@ -167,7 +165,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
self._child_admin_site.register(model, model_admin)
def get_child_models(self):
"""
Return the derived model classes which this admin should handle.
@ -181,7 +178,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
return self.child_models
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.
@ -197,7 +193,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
choices.append((ct.id, model._meta.verbose_name))
return choices
def _get_real_admin(self, object_id):
try:
obj = self.model.objects.non_polymorphic() \
@ -206,7 +201,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
raise Http404
return self._get_real_admin_by_ct(obj['polymorphic_ctype'])
def _get_real_admin_by_ct(self, ct_id):
try:
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)
def _get_real_admin_by_model(self, model_class):
# 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.
@ -233,7 +226,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
except KeyError:
raise ChildAdminNotRegistered("No child admin site was registered for a '{0}' model.".format(model_class))
def get_queryset(self, request):
# optimize the list display.
qs = super(PolymorphicParentModelAdmin, self).get_queryset(request)
@ -241,7 +233,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
qs = qs.non_polymorphic()
return qs
# For Django 1.5:
def queryset(self, request):
qs = super(PolymorphicParentModelAdmin, self).queryset(request)
@ -249,7 +240,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
qs = qs.non_polymorphic()
return qs
def add_view(self, request, form_url='', extra_context=None):
"""Redirect the add view to the real admin."""
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)
def change_view(self, request, object_id, *args, **kwargs):
"""Redirect the change view to the real admin."""
real_admin = self._get_real_admin(object_id)
return real_admin.change_view(request, object_id, *args, **kwargs)
def delete_view(self, request, object_id, extra_context=None):
"""Redirect the delete view to the real admin."""
real_admin = self._get_real_admin(object_id)
@ -331,7 +319,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
return urls + custom_urls + dummy_urls
def subclass_view(self, request, path):
"""
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)
real_admin = self._get_real_admin_by_ct(ct_id)
resolver = RegexURLResolver('^', real_admin.urls)
resolvermatch = resolver.resolve(path) # May raise Resolver404
@ -359,7 +345,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
return resolvermatch.func(request, *resolvermatch.args, **resolvermatch.kwargs)
def add_type_view(self, request, form_url=''):
"""
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)
def render_add_type_form(self, request, context, form_url=''):
"""
Render the page type choice form.
@ -426,7 +410,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
"admin/add_type_form.html"
], context, context_instance=context_instance)
@property
def change_list_template(self):
opts = self.model._meta
@ -446,7 +429,6 @@ class PolymorphicParentModelAdmin(admin.ModelAdmin):
]
class PolymorphicChildModelAdmin(admin.ModelAdmin):
"""
The *optional* base class for the admin interface of derived models.
@ -465,7 +447,6 @@ class PolymorphicChildModelAdmin(admin.ModelAdmin):
base_fieldsets = None
extra_fieldset_title = _("Contents") # Default title for extra fieldset
def get_form(self, request, obj=None, **kwargs):
# The django admin validation requires the form to have a 'class Meta: model = ..'
# 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)
@property
def change_form_template(self):
opts = self.model._meta
@ -502,7 +482,6 @@ class PolymorphicChildModelAdmin(admin.ModelAdmin):
"admin/change_form.html"
]
@property
def delete_confirmation_template(self):
opts = self.model._meta
@ -522,21 +501,18 @@ class PolymorphicChildModelAdmin(admin.ModelAdmin):
"admin/delete_confirmation.html"
]
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
context.update({
'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)
def delete_view(self, request, object_id, context=None):
extra_context = {
'base_opts': self.base_model._meta,
}
return super(PolymorphicChildModelAdmin, self).delete_view(request, object_id, extra_context)
# ---- Extra: improving the form/fieldset default display ----
def get_fieldsets(self, request, obj=None):
@ -557,7 +533,6 @@ class PolymorphicChildModelAdmin(admin.ModelAdmin):
else:
return self.base_fieldsets
def get_subclass_fields(self, request, obj=None):
# Find out how many fields would really be on the form,
# if it weren't restricted by declared fields.

View File

@ -12,7 +12,7 @@ from django.db import models
from django.db.models.base import ModelBase
from django.db.models.manager import ManagerDescriptor
from .manager import PolymorphicManager
from .managers import PolymorphicManager
from .query import PolymorphicQuerySet
# 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):
"""
@ -53,11 +53,11 @@ class PolymorphicModelBase(ModelBase):
"""
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:
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.
# Django 1.5 fixed this, see https://code.djangoproject.com/ticket/19688
attrs['__module__'] = 'django.utils.six'
@ -75,7 +75,7 @@ class PolymorphicModelBase(ModelBase):
# add the managers to the new model
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)
if mgr_name == '_default_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.
user_manager = self.get_first_user_defined_manager(new_class)
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._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),
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_keys = set()
for base in self.__mro__[1:]:
@ -147,7 +147,7 @@ class PolymorphicModelBase(ModelBase):
continue # manager with that name already added, skip
if manager._inherited:
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
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 mgr_list:
_, 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 ) )
return manager
return None
@ -191,9 +191,9 @@ class PolymorphicModelBase(ModelBase):
# app_label here for PolymorphicModel.
meta = attrs.get('Meta', None)
do_app_label_workaround = (meta
and attrs['__module__'] == 'polymorphic'
and model_name == 'PolymorphicModel'
and getattr(meta, 'app_label', None) is None)
and attrs['__module__'] == 'polymorphic'
and model_name == 'PolymorphicModel'
and getattr(meta, 'app_label', None) is None)
if do_app_label_workaround:
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
if 'django/core/management/commands/dumpdata.py' in frm[1]:
return self.base_objects
#caller_mod_name = inspect.getmodule(frm[0]).__name__ # does not work with python 2.4
#if caller_mod_name == 'django.core.management.commands.dumpdata':
# caller_mod_name = inspect.getmodule(frm[0]).__name__ # does not work with python 2.4
# if caller_mod_name == 'django.core.management.commands.dumpdata':
return super(PolymorphicModelBase, self).__getattribute__(name)
# TODO: investigate Django how this can be avoided

View File

@ -1,55 +1,2 @@
# -*- 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
# 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__)
# For compatibility with pre 0.8 versions
from .managers import PolymorphicQuerySet, PolymorphicManager

View File

@ -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)

View File

@ -20,11 +20,12 @@ from django.contrib.contenttypes.models import ContentType
from django.utils import six
from .base import PolymorphicModelBase
from .manager import PolymorphicManager
from .managers import PolymorphicManager
from .query_translate import translate_polymorphic_Q_object
###################################################################################
### PolymorphicModel
# PolymorphicModel
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)
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
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
# issues missing with the ContentType models.
if model is not None \
and not issubclass(model, self.__class__) \
and not issubclass(model, self.__class__._meta.proxy_for_model):
and not issubclass(model, self.__class__) \
and not issubclass(model, self.__class__._meta.proxy_for_model):
raise RuntimeError("ContentType {0} for {1} #{2} does not point to a subclass!".format(
self.polymorphic_ctype_id, model, self.pk,
))
@ -196,31 +197,31 @@ class PolymorphicModel(six.with_metaclass(PolymorphicModelBase, models.Model)):
def add_model_if_regular(model, field_name, result):
if (issubclass(model, models.Model)
and model != models.Model
and model != self.__class__
and model != PolymorphicModel):
and model != models.Model
and model != self.__class__
and model != PolymorphicModel):
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():
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'
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'
add_model_if_regular(super_cls, field_name, result)
add_all_super_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
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
def add_all_sub_models(super_cls, result):
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
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
super_to_sub_related_field = field_to_super.rel
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()
else:
#otherwise use the given related name
# otherwise use the given related name
to_subclass_fieldname = super_to_sub_related_field.related_name
add_model_if_regular(sub_cls, to_subclass_fieldname, result)
result = {}

View File

@ -35,13 +35,13 @@ def transmogrify(cls, obj):
else:
# Run constructor, reassign values
new = cls()
for k,v in obj.__dict__.items():
for k, v in obj.__dict__.items():
new.__dict__[k] = v
return new
###################################################################################
### PolymorphicQuerySet
# PolymorphicQuerySet
def _query_annotations(query):
try:
@ -72,17 +72,17 @@ class PolymorphicQuerySet(QuerySet):
new.polymorphic_disabled = self.polymorphic_disabled
return new
if django.VERSION >= (1,7):
if django.VERSION >= (1, 7):
def as_manager(cls):
# 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._built_with_as_manager = True
return manager
as_manager.queryset_only = True
as_manager = classmethod(as_manager)
def non_polymorphic(self, *args, **kwargs):
def non_polymorphic(self):
"""switch off polymorphic behaviour for this query.
When the queryset is evaluated, only objects of the type of the
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
# (otherwise an error is thrown).
# 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):
"""
@ -333,14 +333,15 @@ class PolymorphicQuerySet(QuerySet):
def __repr__(self, *args, **kwargs):
if self.model.polymorphic_query_multiline_output:
result = [repr(o) for o in self.all()]
return '[ ' + ',\n '.join(result) + ' ]'
return '[ ' + ',\n '.join(result) + ' ]'
else:
return super(PolymorphicQuerySet, self).__repr__(*args, **kwargs)
class _p_list_class(list):
def __repr__(self, *args, **kwargs):
result = [repr(o) for o in self]
return '[ ' + ',\n '.join(result) + ' ]'
return '[ ' + ',\n '.join(result) + ' ]'
def get_real_instances(self, base_result_objects=None):
"same as _get_real_instances, but make sure that __repr__ for ShowField... creates correct output"

View File

@ -4,24 +4,31 @@
"""
from __future__ import absolute_import
import django
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.db.models import Q, FieldDoesNotExist
try:
from django.db.models.related import RelatedObject
except ImportError:
# django.db.models.related.RelatedObject was replaced
# by django.db.models.fields.related.ForeignObjectRel in
# Django 1.8
from django.db.models.fields.related import RelatedField
if django.VERSION < (1, 6):
# There was no common base class in Django 1.5, mention all variants here.
from django.db.models.fields.related import RelatedObject, ManyToOneRel, ManyToManyRel
REL_FIELD_CLASSES = (RelatedField, RelatedObject, ManyToOneRel, ManyToManyRel) # Leaving GenericRel out.
elif django.VERSION < (1, 8):
# As of Django 1.6 there is a ForeignObjectRel.
from django.db.models.fields.related import ForeignObjectRel, RelatedObject
REL_FIELD_CLASSES = (RelatedField, ForeignObjectRel, RelatedObject)
else:
# As of Django 1.8 the base class serves everything. RelatedObject is gone.
from django.db.models.fields.related import ForeignObjectRel
RelatedObject = ForeignObjectRel
REL_FIELD_CLASSES = (RelatedField, ForeignObjectRel)
from functools import reduce
###################################################################################
### PolymorphicQuerySet support functions
# PolymorphicQuerySet support functions
# These functions implement the additional filter- and Q-object functionality.
# 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 _)
# so no tripple ClassName___field was intended.
try:
# rel = (field_object, model, direct, m2m)
field = queryset_model._meta.get_field(classname)
if isinstance(field, RelatedObject):
if django.VERSION >= (1, 8):
# This also retreives M2M relations now (including reverse foreign key relations)
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
# 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.
@ -248,7 +259,7 @@ def _create_model_filter_Q(modellist, not_instance_of=False):
q = q | q_class_with_subclasses(subclass)
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)
if not_instance_of:

View File

@ -3,6 +3,7 @@
from django.db import models
from django.utils import six
class ShowFieldBase(object):
""" base class for the ShowField... model mixins, does the work """
@ -119,8 +120,8 @@ class ShowFieldBase(object):
next_new_section, _, _ = parts[i + 1]
if (self.polymorphic_showfield_max_line_width
and xpos + len(p) > self.polymorphic_showfield_max_line_width
and possible_line_break_pos != None):
and xpos + len(p) > self.polymorphic_showfield_max_line_width
and possible_line_break_pos != None):
rest = out[possible_line_break_pos:]
out = out[:possible_line_break_pos]
out += '\n' + indentstr + rest

View File

@ -5,6 +5,7 @@ register = Library()
class BreadcrumbScope(Node):
def __init__(self, base_opts, nodelist):
self.base_opts = base_opts
self.nodelist = nodelist # Note, takes advantage of Node.child_nodelists
@ -25,7 +26,6 @@ class BreadcrumbScope(Node):
else:
raise TemplateSyntaxError("{0} tag expects 1 argument".format(token.contents[0]))
def render(self, context):
# 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.

View File

@ -14,15 +14,15 @@ except ImportError:
from django.db.models.query import QuerySet
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.contrib.contenttypes.models import ContentType
from django.utils import six
from polymorphic.models import PolymorphicModel
from polymorphic.manager import PolymorphicManager
from polymorphic.managers import PolymorphicManager
from polymorphic.query import PolymorphicQuerySet
from polymorphic import ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent
from polymorphic.showfields import ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent
try:
from django.db.models import UUIDField
except ImportError:
@ -32,94 +32,156 @@ except ImportError:
class PlainA(models.Model):
field1 = models.CharField(max_length=10)
class PlainB(PlainA):
field2 = models.CharField(max_length=10)
class PlainC(PlainB):
field3 = models.CharField(max_length=10)
class Model2A(ShowFieldType, PolymorphicModel):
field1 = models.CharField(max_length=10)
class Model2B(Model2A):
field2 = models.CharField(max_length=10)
class Model2C(Model2B):
field3 = models.CharField(max_length=10)
class Model2D(Model2C):
field4 = models.CharField(max_length=10)
class ModelExtraA(ShowFieldTypeAndContent, PolymorphicModel):
field1 = models.CharField(max_length=10)
class ModelExtraB(ModelExtraA):
field2 = models.CharField(max_length=10)
class ModelExtraC(ModelExtraB):
field3 = models.CharField(max_length=10)
class ModelExtraExternal(models.Model):
topic = models.CharField(max_length=10)
class ModelShow1(ShowFieldType,PolymorphicModel):
class ModelShow1(ShowFieldType, PolymorphicModel):
field1 = models.CharField(max_length=10)
m2m = models.ManyToManyField('self')
class ModelShow2(ShowFieldContent, PolymorphicModel):
field1 = models.CharField(max_length=10)
m2m = models.ManyToManyField('self')
class ModelShow3(ShowFieldTypeAndContent, PolymorphicModel):
field1 = models.CharField(max_length=10)
m2m = models.ManyToManyField('self')
class ModelShow1_plain(PolymorphicModel):
field1 = models.CharField(max_length=10)
class ModelShow2_plain(ModelShow1_plain):
field2 = models.CharField(max_length=10)
class Base(ShowFieldType, PolymorphicModel):
field_b = models.CharField(max_length=10)
class ModelX(Base):
field_x = models.CharField(max_length=10)
class ModelY(Base):
field_y = models.CharField(max_length=10)
class Enhance_Plain(models.Model):
field_p = models.CharField(max_length=10)
class Enhance_Base(ShowFieldTypeAndContent, PolymorphicModel):
base_id = models.AutoField(primary_key=True)
field_b = models.CharField(max_length=10)
class Enhance_Inherit(Enhance_Base, Enhance_Plain):
field_i = models.CharField(max_length=10)
class RelationBase(ShowFieldTypeAndContent, PolymorphicModel):
field_base = models.CharField(max_length=10)
fk = models.ForeignKey('self', null=True, related_name='relationbase_set')
m2m = models.ManyToManyField('self')
class RelationA(RelationBase):
field_a = models.CharField(max_length=10)
class RelationB(RelationBase):
field_b = models.CharField(max_length=10)
class RelationBC(RelationB):
field_c = models.CharField(max_length=10)
class RelatingModel(models.Model):
many2many = models.ManyToManyField(Model2A)
class One2OneRelatingModel(PolymorphicModel):
one2one = models.OneToOneField(Model2A)
field1 = models.CharField(max_length=10)
class One2OneRelatingModelDerived(One2OneRelatingModel):
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):
def my_queryset_foo(self):
return self.all() # Just a method to prove the existance of the custom queryset.
class MyManager(PolymorphicManager):
queryset_class = MyManagerQuerySet
def get_queryset(self):
return super(MyManager, self).get_queryset().order_by('-field1')
def my_queryset_foo(self):
return self.all().my_queryset_foo()
# Django <= 1.5 compatibility
get_query_set = get_queryset
class ModelWithMyManager(ShowFieldTypeAndContent, Model2A):
objects = MyManager()
field4 = models.CharField(max_length=10)
@ -136,23 +198,33 @@ class ModelWithMyManagerDefault(ShowFieldTypeAndContent, Model2A):
field4 = models.CharField(max_length=10)
if django.VERSION >= (1,7):
if django.VERSION >= (1, 7):
class ModelWithMyManager2(ShowFieldTypeAndContent, Model2A):
objects = MyManagerQuerySet.as_manager()
field4 = models.CharField(max_length=10)
class MROBase1(ShowFieldType, PolymorphicModel):
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):
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):
objects = PolymorphicManager()
class MRODerived(MROBase2, MROBase3):
pass
class ParentModelWithManager(PolymorphicModel):
pass
class ChildModelWithManager(PolymorphicModel):
# Also test whether foreign keys receive the manager:
fk = models.ForeignKey(ParentModelWithManager, related_name='childmodel_set')
@ -160,10 +232,13 @@ class ChildModelWithManager(PolymorphicModel):
class PlainMyManagerQuerySet(QuerySet):
def my_queryset_foo(self):
return self.all() # Just a method to prove the existance of the custom queryset.
class PlainMyManager(models.Manager):
def my_queryset_foo(self):
return self.get_queryset().my_queryset_foo()
@ -173,9 +248,11 @@ class PlainMyManager(models.Manager):
# Django <= 1.5 compatibility
get_query_set = get_queryset
class PlainParentModelWithManager(models.Model):
pass
class PlainChildModelWithManager(models.Model):
fk = models.ForeignKey(PlainParentModelWithManager, related_name='childmodel_set')
objects = PlainMyManager()
@ -185,88 +262,138 @@ class MgrInheritA(models.Model):
mgrA = models.Manager()
mgrA2 = models.Manager()
field1 = models.CharField(max_length=10)
class MgrInheritB(MgrInheritA):
mgrB = models.Manager()
field2 = models.CharField(max_length=10)
class MgrInheritC(ShowFieldTypeAndContent, MgrInheritB):
pass
class BlogBase(ShowFieldTypeAndContent, PolymorphicModel):
name = models.CharField(max_length=10)
class BlogA(BlogBase):
info = models.CharField(max_length=10)
class BlogB(BlogBase):
pass
class BlogEntry(ShowFieldTypeAndContent, PolymorphicModel):
blog = models.ForeignKey(BlogA)
text = models.CharField(max_length=10)
class BlogEntry_limit_choices_to(ShowFieldTypeAndContent, PolymorphicModel):
blog = models.ForeignKey(BlogBase)
text = models.CharField(max_length=10)
class ModelFieldNameTest(ShowFieldType, PolymorphicModel):
modelfieldnametest = models.CharField(max_length=10)
class InitTestModel(ShowFieldType, PolymorphicModel):
bar = models.CharField(max_length=100)
def __init__(self, *args, **kwargs):
kwargs['bar'] = self.x()
super(InitTestModel, self).__init__(*args, **kwargs)
class InitTestModelSubclass(InitTestModel):
def x(self):
return 'XYZ'
# models from github issue
class Top(PolymorphicModel):
name = models.CharField(max_length=50)
class Meta:
ordering = ('pk',)
class Middle(Top):
description = models.TextField()
class Bottom(Middle):
author = models.CharField(max_length=50)
class UUIDProject(ShowFieldTypeAndContent, PolymorphicModel):
uuid_primary_key = UUIDField(primary_key = True, default=uuid.uuid1)
topic = models.CharField(max_length = 30)
uuid_primary_key = UUIDField(primary_key=True, default=uuid.uuid1)
topic = models.CharField(max_length=30)
class UUIDArtProject(UUIDProject):
artist = models.CharField(max_length = 30)
artist = models.CharField(max_length=30)
class UUIDResearchProject(UUIDProject):
supervisor = models.CharField(max_length = 30)
supervisor = models.CharField(max_length=30)
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)
class UUIDPlainB(UUIDPlainA):
field2 = models.CharField(max_length=10)
class UUIDPlainC(UUIDPlainB):
field3 = models.CharField(max_length=10)
# base -> proxy
class ProxyBase(PolymorphicModel):
some_data = models.CharField(max_length=128)
class ProxyChild(ProxyBase):
class Meta:
proxy = True
class NonProxyChild(ProxyBase):
name=models.CharField(max_length=10)
name = models.CharField(max_length=10)
# base -> proxy -> real models
class ProxiedBase(ShowFieldTypeAndContent, PolymorphicModel):
name = models.CharField(max_length=10)
class ProxyModelBase(ProxiedBase):
class Meta:
proxy = True
class ProxyModelA(ProxyModelBase):
field1 = models.CharField(max_length=10)
class ProxyModelB(ProxyModelBase):
field2 = models.CharField(max_length=10)
# test bad field name
#class TestBadFieldModel(ShowFieldType, PolymorphicModel):
# class TestBadFieldModel(ShowFieldType, PolymorphicModel):
# instance_of = models.CharField(max_length=10)
# validation error: "polymorphic.relatednameclash: Accessor for field 'polymorphic_ctype' clashes
@ -275,12 +402,17 @@ class ProxyModelB(ProxyModelBase):
class RelatedNameClash(ShowFieldType, PolymorphicModel):
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):
superclass = models.OneToOneField(ModelShow1_plain, parent_link=True, related_name='related_name_subclass')
class CustomPkBase(ShowFieldTypeAndContent, PolymorphicModel):
b = models.CharField(max_length=1)
class CustomPkInherit(CustomPkBase):
custom_id = models.AutoField(primary_key=True)
i = models.CharField(max_length=1)
@ -335,7 +467,7 @@ class PolymorphicTests(TestCase):
# test ordering for field in one subclass only
# MySQL and SQLite return this order
expected1='''
expected1 = '''
[ <BlogA: id 8, name (CharField) "B5", info (CharField) "i5">,
<BlogA: id 7, name (CharField) "B4", info (CharField) "i4">,
<BlogA: id 6, name (CharField) "B3", info (CharField) "i3">,
@ -346,7 +478,7 @@ class PolymorphicTests(TestCase):
<BlogB: id 4, name (CharField) "Bb3"> ]'''
# PostgreSQL returns this order
expected2='''
expected2 = '''
[ <BlogB: id 2, name (CharField) "Bb1">,
<BlogB: id 3, name (CharField) "Bb2">,
<BlogB: id 4, name (CharField) "Bb3">,
@ -359,7 +491,6 @@ class PolymorphicTests(TestCase):
x = '\n' + repr(BlogBase.objects.order_by('-BlogA___info'))
self.assertTrue(x == expected1 or x == expected2)
def test_limit_choices_to(self):
"""
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')
entry2 = BlogEntry_limit_choices_to.objects.create(blog=blog_b, text='bla2')
def test_primary_key_custom_field_problem(self):
"""
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.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">,
<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"> ]"""
@ -413,7 +543,6 @@ class PolymorphicTests(TestCase):
Model2C.objects.create(field1='C1', field2='C2', field3='C3')
Model2D.objects.create(field1='D1', field2='D2', field3='D3', field4='D4')
def test_simple_inheritance(self):
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[3]), '<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField)>')
def test_manual_get_real_instance(self):
self.create_model2abcd()
o = Model2A.objects.non_polymorphic().get(field1='C1')
self.assertEqual(repr(o.get_real_instance()), '<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>')
def test_non_polymorphic(self):
self.create_model2abcd()
@ -440,7 +567,6 @@ class PolymorphicTests(TestCase):
self.assertEqual(repr(objects[2]), '<Model2A: id 3, field1 (CharField)>')
self.assertEqual(repr(objects[3]), '<Model2A: id 4, field1 (CharField)>')
def test_get_real_instances(self):
self.create_model2abcd()
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[3]), '<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField)>')
def test_translate_polymorphic_q_object(self):
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[1]), '<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField)>')
def test_base_manager(self):
def show_base_manager(model):
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(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(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'>")
def test_instance_default_manager(self):
def show_default_manager(instance):
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_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_2b), "<class 'polymorphic.manager.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_2a), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.Model2A'>")
self.assertEqual(show_default_manager(model_2b), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.Model2B'>")
self.assertEqual(show_default_manager(model_2c), "<class 'polymorphic.managers.PolymorphicManager'> <class 'polymorphic.tests.Model2C'>")
def test_foreignkey_field(self):
self.create_model2abcd()
@ -520,7 +643,6 @@ class PolymorphicTests(TestCase):
object2b = Model2B.base_objects.get(field1='C1')
self.assertEqual(repr(object2b.model2c), '<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>')
def test_onetoone_field(self):
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(a.one2onerelatingmodel), '<One2OneRelatingModelDerived: One2OneRelatingModelDerived object>')
def test_manytomany_field(self):
# Model 1
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> ]')
# Model 3
o=ModelShow3.objects.create(field1='abc')
o = ModelShow3.objects.create(field1='abc')
o.m2m.add(o)
o.save()
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')
self.assertEqual(repr(ModelShow1_plain.objects.all()), '[<ModelShow1_plain: ModelShow1_plain object>, <ModelShow2_plain: ModelShow2_plain object>]')
def test_extra_method(self):
self.create_model2abcd()
@ -581,7 +701,7 @@ class PolymorphicTests(TestCase):
ModelExtraExternal.objects.create(topic='extra1')
ModelExtraExternal.objects.create(topic='extra2')
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:
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">')
@ -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(len(objects), 3)
def test_instance_of_filter(self):
self.create_model2abcd()
@ -618,15 +737,29 @@ class PolymorphicTests(TestCase):
self.assertEqual(repr(objects[0]), '<Model2A: id 1, field1 (CharField)>')
self.assertEqual(len(objects), 1)
def test_polymorphic___filter(self):
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(repr(objects[0]), '<Model2B: id 2, field1 (CharField), field2 (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):
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(len(objects), 3)
def test_combine_querysets(self):
ModelX.objects.create(field_x='x')
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(len(qs), 2)
def test_multiple_inheritance(self):
# 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(len(objects), 2)
def test_user_defined_manager(self):
self.create_model2abcd()
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.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):
self.create_model2abcd()
ModelWithMyManager2.objects.create(field1='D1a', field4='D4a')
@ -752,7 +882,6 @@ class PolymorphicTests(TestCase):
self.assertEqual(type(ModelWithMyManager2._default_manager).__name__, 'PolymorphicManagerFromMyManagerQuerySet')
self.assertIs(type(ModelWithMyManager2.base_objects), models.Manager)
def test_manager_inheritance(self):
# by choice of MRO, should be MyManager from MROBase1.
self.assertIs(type(MRODerived.objects), MyManager)
@ -763,7 +892,6 @@ class PolymorphicTests(TestCase):
# Django vanilla inheritance does not inherit MyManager as _default_manager here
self.assertIs(type(MROBase2._default_manager), MyManager)
def test_queryset_assignment(self):
# This is just a consistency check for now, testing standard Django behavior.
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.
self.assertIs(type(parent.childmodel_set.my_queryset_foo()), MyManagerQuerySet)
def test_proxy_models(self):
# prepare some data
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,
proxy child models need to be handled separately.
"""
name="Item1"
name = "Item1"
nonproxychild = NonProxyChild.objects.create(name=name)
pb = ProxyBase.objects.get(id=1)
@ -829,7 +956,6 @@ class PolymorphicTests(TestCase):
ct = ContentType.objects.get_for_model(ProxyChild, for_concrete_model=False)
self.assertEqual(ProxyChild, ct.model_class())
def test_proxy_model_inheritance(self):
"""
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">')
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')
self.assertEqual(repr(o), '<ModelFieldNameTest: id 1, modelfieldnametest (CharField)>')
@ -883,21 +1009,20 @@ class PolymorphicTests(TestCase):
t.save()
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.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")
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.related_name_subclass, t)
#test that we can delete the object
# test that we can delete the object
t.delete()
class RegressionTests(TestCase):
def test_for_query_result_incomplete_with_inheritance(self):
@ -918,4 +1043,3 @@ class RegressionTests(TestCase):
expected_queryset = [bottom]
self.assertQuerysetEqual(Bottom.objects.all(), [repr(r) for r in expected_queryset])

View File

@ -63,7 +63,7 @@ class UUIDField(six.with_metaclass(models.SubfieldBase, models.CharField)):
self.namespace, self.name = namespace, name
super(UUIDField, self).__init__(verbose_name=verbose_name,
name=name, **kwargs)
name=name, **kwargs)
def create_uuid(self):
if not self.version or self.version == 4:
@ -103,11 +103,11 @@ class UUIDField(six.with_metaclass(models.SubfieldBase, models.CharField)):
# instance), everything works.
#
#if not value:
# if not value:
# return None
#if isinstance(value, uuid.UUID):
# if isinstance(value, uuid.UUID):
# return smart_text(value)
#else:
# else:
# return value
def pre_save(self, model_instance, add):
@ -139,6 +139,6 @@ class UUIDField(six.with_metaclass(models.SubfieldBase, models.CharField)):
defaults = {
'form_class': forms.CharField,
'max_length': self.max_length
}
}
defaults.update(kwargs)
return super(UUIDField, self).formfield(**defaults)

View File

@ -19,15 +19,15 @@ sys.stderr.write('Using Django version {0} from {1}\n'.format(
if not settings.configured:
settings.configure(
DEBUG = True,
TEMPLATE_DEBUG = True,
DATABASES = {
DEBUG=True,
TEMPLATE_DEBUG=True,
DATABASES={
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:'
}
},
TEMPLATE_LOADERS = (
TEMPLATE_LOADERS=(
'django.template.loaders.app_directories.Loader',
),
TEMPLATE_CONTEXT_PROCESSORS=(
@ -37,7 +37,7 @@ if not settings.configured:
'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 = (
'django.contrib.auth',
'django.contrib.contenttypes',
@ -50,9 +50,15 @@ if not settings.configured:
SITE_ID = 3,
)
DEFAULT_TEST_APPS = [
'polymorphic',
]
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)
if __name__ == '__main__':

View File

@ -21,22 +21,22 @@ def find_version(*parts):
setup(
name = 'django_polymorphic',
version = find_version('polymorphic', '__version__.py'),
license = 'BSD',
name='django_polymorphic',
version=find_version('polymorphic', '__init__.py'),
license='BSD',
description = 'Seamless Polymorphic Inheritance for Django Models',
long_description = read('README.rst'),
url = 'https://github.com/chrisglass/django_polymorphic',
description='Seamless Polymorphic Inheritance for Django Models',
long_description=read('README.rst'),
url='https://github.com/chrisglass/django_polymorphic',
author = 'Bert Constantin',
author_email = 'bert.constantin@gmx.de',
author='Bert Constantin',
author_email='bert.constantin@gmx.de',
maintainer = 'Christopher Glass',
maintainer_email = 'tribaal@gmail.com',
maintainer='Christopher Glass',
maintainer_email='tribaal@gmail.com',
packages = find_packages(),
package_data = {
packages=find_packages(),
package_data={
'polymorphic': [
'templates/admin/polymorphic/*.html',
],

View File

@ -22,6 +22,6 @@ commands=
python runtests.py
[testenv:docs]
changedir=docs
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