Rewrite translate_polymorphic_field_path() avoid closures
Inspired by PR #259 to look at thisfix_request_path_info
parent
9225f08141
commit
17e41c4f7f
|
|
@ -5,9 +5,11 @@ PolymorphicQuerySet support functions
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
from collections import deque
|
||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from django.core.exceptions import FieldError
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.db.models.fields.related import ForeignObjectRel, RelatedField
|
from django.db.models.fields.related import ForeignObjectRel, RelatedField
|
||||||
|
|
@ -166,41 +168,10 @@ def translate_polymorphic_field_path(queryset_model, field_path):
|
||||||
except models.FieldDoesNotExist:
|
except models.FieldDoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# function to collect all sub-models, this should be optimized (cached)
|
submodels = _get_all_sub_models(queryset_model)
|
||||||
def add_all_sub_models(model, result):
|
|
||||||
if issubclass(model, models.Model) and model != models.Model:
|
|
||||||
# model name is occurring twice in submodel inheritance tree => Error
|
|
||||||
if model.__name__ in result and model != result[model.__name__]:
|
|
||||||
e = 'PolymorphicModel: model name alone is ambiguous: %s.%s and %s.%s!\n'
|
|
||||||
e += 'In this case, please use the syntax: applabel__ModelName___field'
|
|
||||||
assert model, e % (
|
|
||||||
model._meta.app_label, model.__name__,
|
|
||||||
result[model.__name__]._meta.app_label, result[model.__name__].__name__)
|
|
||||||
|
|
||||||
result[model.__name__] = model
|
|
||||||
|
|
||||||
for b in model.__subclasses__():
|
|
||||||
add_all_sub_models(b, result)
|
|
||||||
|
|
||||||
submodels = {}
|
|
||||||
add_all_sub_models(queryset_model, submodels)
|
|
||||||
model = submodels.get(classname, None)
|
model = submodels.get(classname, None)
|
||||||
assert model, 'PolymorphicModel: model %s not found (not a subclass of %s)!' % (classname, queryset_model.__name__)
|
assert model, 'PolymorphicModel: model %s not found (not a subclass of %s)!' % (classname, queryset_model.__name__)
|
||||||
|
|
||||||
# create new field path for expressions, e.g. for baseclass=ModelA, myclass=ModelC
|
|
||||||
# 'modelb__modelc" is returned
|
|
||||||
def _create_base_path(baseclass, myclass):
|
|
||||||
bases = myclass.__bases__
|
|
||||||
for b in bases:
|
|
||||||
if b == baseclass:
|
|
||||||
return myclass.__name__.lower()
|
|
||||||
path = _create_base_path(baseclass, b)
|
|
||||||
if path:
|
|
||||||
if b._meta.abstract or b._meta.proxy:
|
|
||||||
return myclass.__name__.lower()
|
|
||||||
return path + '__' + myclass.__name__.lower()
|
|
||||||
return ''
|
|
||||||
|
|
||||||
basepath = _create_base_path(queryset_model, model)
|
basepath = _create_base_path(queryset_model, model)
|
||||||
|
|
||||||
if negated:
|
if negated:
|
||||||
|
|
@ -216,6 +187,50 @@ def translate_polymorphic_field_path(queryset_model, field_path):
|
||||||
return newpath
|
return newpath
|
||||||
|
|
||||||
|
|
||||||
|
def _get_all_sub_models(base_model):
|
||||||
|
"""#Collect all sub-models, this should be optimized (cached)"""
|
||||||
|
result = {}
|
||||||
|
queue = deque([base_model])
|
||||||
|
|
||||||
|
while queue:
|
||||||
|
model = queue.popleft()
|
||||||
|
if issubclass(model, models.Model) and model != models.Model:
|
||||||
|
# model name is occurring twice in submodel inheritance tree => Error
|
||||||
|
if model.__name__ in result and model != result[model.__name__]:
|
||||||
|
raise FieldError(
|
||||||
|
'PolymorphicModel: model name alone is ambiguous: %s.%s and %s.%s match!\n'
|
||||||
|
'In this case, please use the syntax: applabel__ModelName___field' % (
|
||||||
|
model._meta.app_label, model.__name__,
|
||||||
|
result[model.__name__]._meta.app_label,
|
||||||
|
result[model.__name__].__name__
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
result[model.__name__] = model
|
||||||
|
queue.extend(model.__subclasses__())
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _create_base_path(baseclass, myclass):
|
||||||
|
# create new field path for expressions, e.g. for baseclass=ModelA, myclass=ModelC
|
||||||
|
# 'modelb__modelc" is returned
|
||||||
|
bases = myclass.__bases__
|
||||||
|
for b in bases:
|
||||||
|
if b == baseclass:
|
||||||
|
return _get_query_related_name(myclass)
|
||||||
|
path = _create_base_path(baseclass, b)
|
||||||
|
if path:
|
||||||
|
if b._meta.abstract or b._meta.proxy:
|
||||||
|
return myclass.__name__.lower()
|
||||||
|
return path + '__' + _get_query_related_name(myclass)
|
||||||
|
return ''
|
||||||
|
|
||||||
|
|
||||||
|
def _get_query_related_name(myclass):
|
||||||
|
return myclass.__name__.lower()
|
||||||
|
|
||||||
|
|
||||||
def create_instanceof_q(modellist, not_instance_of=False, using=DEFAULT_DB_ALIAS):
|
def create_instanceof_q(modellist, not_instance_of=False, using=DEFAULT_DB_ALIAS):
|
||||||
"""
|
"""
|
||||||
Helper function for instance_of / not_instance_of
|
Helper function for instance_of / not_instance_of
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue