Model___field notation now automatically chooses correct application + separated translation into own function
parent
1ba36e9fb1
commit
f77ebe8149
|
|
@ -11,4 +11,5 @@ pushhg
|
||||||
pushreg
|
pushreg
|
||||||
mypoly.py
|
mypoly.py
|
||||||
tmp
|
tmp
|
||||||
|
poly2.py
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -228,12 +228,14 @@ Manager Inheritance
|
||||||
|
|
||||||
The current polymorphic models implementation unconditionally
|
The current polymorphic models implementation unconditionally
|
||||||
inherits all managers from its base models (but only the
|
inherits all managers from its base models (but only the
|
||||||
polymorphic ones). An example::
|
polymorphic base models).
|
||||||
|
|
||||||
|
An example (inheriting from MyModel above)::
|
||||||
|
|
||||||
class MyModel2(MyModel):
|
class MyModel2(MyModel):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Managers inherited from MyModel, delivering MyModel2 objects
|
# Managers inherited from MyModel, delivering MyModel2 objects (including MyModel2 subclass objects)
|
||||||
>>> MyModel2.objects.all()
|
>>> MyModel2.objects.all()
|
||||||
>>> MyModel2.ordered_objects.all()
|
>>> MyModel2.ordered_objects.all()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -743,19 +743,56 @@ def _translate_polymorphic_filter_spec(queryset_model, field_path, field_val):
|
||||||
return _create_model_filter_Q(field_val, not_instance_of=True)
|
return _create_model_filter_Q(field_val, not_instance_of=True)
|
||||||
elif not '___' in field_path:
|
elif not '___' in field_path:
|
||||||
return None #no change
|
return None #no change
|
||||||
|
|
||||||
# filter expression contains '___' (i.e. filter for polymorphic field)
|
# filter expression contains '___' (i.e. filter for polymorphic field)
|
||||||
# => get the model class specified in the filter expression
|
# => get the model class specified in the filter expression
|
||||||
# TODO: if app not given, just model name => try to find model in any app??
|
newpath = _translate_polymorphic_field_path(queryset_model, field_path)
|
||||||
classname, sep, pure_field_path = field_path.partition('___')
|
return (newpath, field_val)
|
||||||
if '__' in classname: appname, sep, classname = classname.partition('__')
|
|
||||||
else: appname = queryset_model._meta.app_label
|
|
||||||
model = models.get_model(appname, classname)
|
def _translate_polymorphic_field_path(queryset_model, field_path):
|
||||||
assert model, 'model %s (in app %s) not found!' % (modelname, appname)
|
"""
|
||||||
if not issubclass(model, queryset_model):
|
Translate a field path from keyword argument, as used for
|
||||||
e = 'queryset filter error: "' + model.__name__ + '" is not derived from "' + queryset_model.__name__ + '"'
|
PolymorphicQuerySet.filter()-like functions (and Q objects).
|
||||||
raise AssertionError(e)
|
|
||||||
|
|
||||||
|
E.g.: ModelC___field3 is translated into modela__modelb__modelc__field3
|
||||||
|
Returns: translated path
|
||||||
|
"""
|
||||||
|
classname, sep, pure_field_path = field_path.partition('___')
|
||||||
|
assert sep == '___'
|
||||||
|
|
||||||
|
if '__' in classname:
|
||||||
|
# the user has app label prepended to class name via __ => use Django's get_model function
|
||||||
|
appname, sep, classname = classname.partition('__')
|
||||||
|
model = models.get_model(appname, classname)
|
||||||
|
assert model, 'model %s (in app %s) not found!' % (model.__name__, appname)
|
||||||
|
if not issubclass(model, queryset_model):
|
||||||
|
e = 'queryset filter error: "' + model.__name__ + '" is not derived from "' + queryset_model.__name__ + '"'
|
||||||
|
raise AssertionError(e)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# the user has only given us the class name via __
|
||||||
|
# => select the model from the sub models of the queryset base model
|
||||||
|
|
||||||
|
# function to collect all sub-models, this could be optimized
|
||||||
|
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__]:
|
||||||
|
assert model, 'model name is ambiguous: %s.%s, %s.%s!' % (
|
||||||
|
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)
|
||||||
|
assert model, 'model %s not found (not a subclass of %s)!' % (model.__name__, queryset_model.__name__)
|
||||||
|
|
||||||
# create new field path for expressions, e.g. for baseclass=ModelA, myclass=ModelC
|
# create new field path for expressions, e.g. for baseclass=ModelA, myclass=ModelC
|
||||||
# 'modelb__modelc" is returned
|
# 'modelb__modelc" is returned
|
||||||
def _create_base_path(baseclass, myclass):
|
def _create_base_path(baseclass, myclass):
|
||||||
|
|
@ -770,7 +807,8 @@ def _translate_polymorphic_filter_spec(queryset_model, field_path, field_val):
|
||||||
basepath = _create_base_path(queryset_model, model)
|
basepath = _create_base_path(queryset_model, model)
|
||||||
newpath = basepath + '__' if basepath else ''
|
newpath = basepath + '__' if basepath else ''
|
||||||
newpath += pure_field_path
|
newpath += pure_field_path
|
||||||
return (newpath, field_val)
|
return newpath
|
||||||
|
|
||||||
|
|
||||||
def _create_model_filter_Q(modellist, not_instance_of=False):
|
def _create_model_filter_Q(modellist, not_instance_of=False):
|
||||||
"""
|
"""
|
||||||
|
|
@ -1037,4 +1075,3 @@ class PolymorphicModel(models.Model):
|
||||||
if f != last: out += ', '
|
if f != last: out += ', '
|
||||||
return '<' + out + '>'
|
return '<' + out + '>'
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue