Rewrite translate_polymorphic_field_path() avoid closures

Inspired by PR #259 to look at this
fix_request_path_info
Diederik van der Boor 2019-07-12 11:37:13 +02:00
parent 9225f08141
commit 17e41c4f7f
No known key found for this signature in database
GPG Key ID: 4FA014E0305E73C1
1 changed files with 47 additions and 32 deletions

View File

@ -5,9 +5,11 @@ PolymorphicQuerySet support functions
from __future__ import absolute_import
import copy
from collections import deque
from django.apps import apps
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import FieldError
from django.db import models
from django.db.models import Q
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:
pass
# function to collect all sub-models, this should be optimized (cached)
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)
submodels = _get_all_sub_models(queryset_model)
model = submodels.get(classname, None)
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)
if negated:
@ -216,6 +187,50 @@ def translate_polymorphic_field_path(queryset_model, field_path):
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):
"""
Helper function for instance_of / not_instance_of