2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
This implements the common managers that are used by the
|
|
|
|
|
abstract models in dbobjects.py (and which are thus shared by
|
2012-03-30 23:47:22 +02:00
|
|
|
all Attributes and TypedObjects).
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2012-03-27 09:59:11 +02:00
|
|
|
from functools import update_wrapper
|
2010-08-29 18:46:58 +00:00
|
|
|
from django.db import models
|
2013-07-12 11:12:21 +02:00
|
|
|
from django.db.models import Q
|
2014-02-16 13:19:31 +01:00
|
|
|
from django.contrib.contenttypes.models import ContentType
|
2010-10-31 08:10:02 +00:00
|
|
|
from src.utils import idmapper
|
2014-04-21 15:18:13 +02:00
|
|
|
from src.utils.utils import make_iter, variable_from_module
|
2013-04-14 16:36:44 +02:00
|
|
|
from src.utils.dbserialize import to_pickle
|
|
|
|
|
|
2012-03-31 15:09:22 +02:00
|
|
|
__all__ = ("AttributeManager", "TypedObjectManager")
|
2013-07-08 18:13:21 +02:00
|
|
|
_GA = object.__getattribute__
|
2013-12-02 15:40:02 +01:00
|
|
|
_ObjectDB = None
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2014-02-16 22:09:35 +01:00
|
|
|
#
|
|
|
|
|
# helper functions for the TypedObjectManager.
|
|
|
|
|
#
|
|
|
|
|
|
|
|
|
|
def returns_typeclass_list(method):
|
|
|
|
|
"""
|
|
|
|
|
Decorator: Changes return of the decorated method (which are
|
|
|
|
|
TypeClassed objects) into object_classes(s) instead. Will always
|
|
|
|
|
return a list (may be empty).
|
|
|
|
|
"""
|
|
|
|
|
def func(self, *args, **kwargs):
|
|
|
|
|
"decorator. Returns a list."
|
|
|
|
|
self.__doc__ = method.__doc__
|
|
|
|
|
matches = make_iter(method(self, *args, **kwargs))
|
|
|
|
|
return [(hasattr(dbobj, "typeclass") and dbobj.typeclass) or dbobj
|
|
|
|
|
for dbobj in make_iter(matches)]
|
|
|
|
|
return update_wrapper(func, method)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def returns_typeclass(method):
|
|
|
|
|
"""
|
|
|
|
|
Decorator: Will always return a single typeclassed result or None.
|
|
|
|
|
"""
|
|
|
|
|
def func(self, *args, **kwargs):
|
|
|
|
|
"decorator. Returns result or None."
|
|
|
|
|
self.__doc__ = method.__doc__
|
|
|
|
|
matches = method(self, *args, **kwargs)
|
|
|
|
|
dbobj = matches and make_iter(matches)[0] or None
|
|
|
|
|
if dbobj:
|
|
|
|
|
return (hasattr(dbobj, "typeclass") and dbobj.typeclass) or dbobj
|
|
|
|
|
return None
|
|
|
|
|
return update_wrapper(func, method)
|
|
|
|
|
|
2012-03-30 23:47:22 +02:00
|
|
|
# Managers
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2013-04-14 16:36:44 +02:00
|
|
|
def _attr_pickled(method):
|
|
|
|
|
"""
|
|
|
|
|
decorator for safely handling attribute searches
|
|
|
|
|
- db_value is a pickled field and this is required
|
|
|
|
|
in order to be able for pickled django objects directly.
|
|
|
|
|
"""
|
|
|
|
|
def wrapper(self, *args, **kwargs):
|
|
|
|
|
"wrap all queries searching the db_value field in some way"
|
|
|
|
|
self.__doc__ = method.__doc__
|
|
|
|
|
for key in (key for key in kwargs if key.startswith('db_value')):
|
|
|
|
|
kwargs[key] = to_pickle(kwargs[key])
|
|
|
|
|
return method(self, *args, **kwargs)
|
|
|
|
|
return update_wrapper(wrapper, method)
|
|
|
|
|
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
class AttributeManager(models.Manager):
|
|
|
|
|
"Manager for handling Attributes."
|
2013-04-14 16:36:44 +02:00
|
|
|
@_attr_pickled
|
|
|
|
|
def get(self, *args, **kwargs):
|
|
|
|
|
return super(AttributeManager, self).get(*args, **kwargs)
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2014-07-05 20:32:08 +02:00
|
|
|
@_attr_pickled
|
2013-04-14 16:36:44 +02:00
|
|
|
def filter(self,*args, **kwargs):
|
|
|
|
|
return super(AttributeManager, self).filter(*args, **kwargs)
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2014-07-05 20:32:08 +02:00
|
|
|
@_attr_pickled
|
2013-04-14 16:36:44 +02:00
|
|
|
def exclude(self,*args, **kwargs):
|
|
|
|
|
return super(AttributeManager, self).exclude(*args, **kwargs)
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2014-07-05 20:32:08 +02:00
|
|
|
@_attr_pickled
|
2013-04-14 16:36:44 +02:00
|
|
|
def values(self,*args, **kwargs):
|
|
|
|
|
return super(AttributeManager, self).values(*args, **kwargs)
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2014-07-05 20:32:08 +02:00
|
|
|
@_attr_pickled
|
2013-04-14 16:36:44 +02:00
|
|
|
def values_list(self,*args, **kwargs):
|
|
|
|
|
return super(AttributeManager, self).values_list(*args, **kwargs)
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2014-07-05 20:32:08 +02:00
|
|
|
@_attr_pickled
|
2013-04-14 16:36:44 +02:00
|
|
|
def exists(self,*args, **kwargs):
|
|
|
|
|
return super(AttributeManager, self).exists(*args, **kwargs)
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2013-08-24 21:23:43 +02:00
|
|
|
def get_attrs_on_obj(self, searchstr, obj, category=None, exact_match=True):
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2013-07-08 18:13:21 +02:00
|
|
|
Searches the object's attributes for attribute key matches.
|
2012-03-30 23:47:22 +02:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
searchstr: (str) A string to search for.
|
|
|
|
|
"""
|
|
|
|
|
# Retrieve the list of attributes for this object.
|
2013-07-08 18:13:21 +02:00
|
|
|
|
2013-08-24 21:23:43 +02:00
|
|
|
category_cond = Q(db_category__iexact=category) if category else Q()
|
2010-08-29 18:46:58 +00:00
|
|
|
if exact_match:
|
2013-08-24 21:23:43 +02:00
|
|
|
return _GA("obj", "db_attributes").filter(db_key__iexact=searchstr & category_cond)
|
2010-08-29 18:46:58 +00:00
|
|
|
else:
|
2013-08-24 21:23:43 +02:00
|
|
|
return _GA("obj", "db_attributes").filter(db_key__icontains=searchstr & category_cond)
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2013-07-12 11:12:21 +02:00
|
|
|
def attr_namesearch(self, *args, **kwargs):
|
|
|
|
|
"alias wrapper for backwards compatability"
|
|
|
|
|
return self.get_attrs_on_obj(*args, **kwargs)
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2013-07-12 11:12:21 +02:00
|
|
|
def get_attr_by_value(self, searchstr, obj=None):
|
2013-04-14 16:36:44 +02:00
|
|
|
"""
|
2013-07-08 18:13:21 +02:00
|
|
|
Searches obj for Attributes with a given value.
|
|
|
|
|
searchstr - value to search for. This may be any suitable object.
|
|
|
|
|
obj - limit to a given object instance
|
|
|
|
|
|
|
|
|
|
If no restraint is given, all Attributes on all types of objects
|
|
|
|
|
will be searched. It's highly recommended to at least
|
|
|
|
|
supply the objclass argument (DBObject, DBScript or DBPlayer)
|
|
|
|
|
to restrict this lookup.
|
2013-04-14 16:36:44 +02:00
|
|
|
"""
|
|
|
|
|
if obj:
|
2013-07-08 18:13:21 +02:00
|
|
|
return _GA(obj, "db_attributes").filter(db_value=searchstr)
|
2013-04-14 16:36:44 +02:00
|
|
|
return self.filter(db_value=searchstr)
|
|
|
|
|
|
2013-07-12 11:12:21 +02:00
|
|
|
def attr_valuesearch(self, *args, **kwargs):
|
|
|
|
|
"alias wrapper for backwards compatability"
|
|
|
|
|
return self.get_attr_by_value(self, *args, **kwargs)
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# TagManager
|
|
|
|
|
#
|
|
|
|
|
|
|
|
|
|
class TagManager(models.Manager):
|
|
|
|
|
"""
|
|
|
|
|
Extra manager methods for Tags
|
|
|
|
|
"""
|
2013-07-12 20:21:52 +02:00
|
|
|
def get_tags_on_obj(self, obj, key=None, category=None):
|
2013-07-12 11:12:21 +02:00
|
|
|
"""
|
|
|
|
|
Get all tags on obj, optionally limited by key and/or category
|
|
|
|
|
"""
|
2013-08-04 12:47:00 -05:00
|
|
|
tags = _GA(obj, "db_tags").all()
|
|
|
|
|
if key:
|
|
|
|
|
tags = tags.filter(db_key__iexact=key.lower().strip())
|
|
|
|
|
if category:
|
|
|
|
|
tags = tags.filter(db_category__iexact=category.lower().strip())
|
|
|
|
|
return list(tags)
|
2013-07-12 11:12:21 +02:00
|
|
|
|
2014-02-16 13:19:31 +01:00
|
|
|
def get_tag(self, key=None, category=None, model="objects.objectdb", tagtype=None):
|
2013-07-12 11:12:21 +02:00
|
|
|
"""
|
|
|
|
|
Search and return all tags matching any combination of
|
|
|
|
|
the search criteria.
|
|
|
|
|
search_key (string) - the tag identifier
|
|
|
|
|
category (string) - the tag category
|
2014-02-16 13:19:31 +01:00
|
|
|
model - the type of object tagged, on naturalkey form, like "objects.objectdb"
|
|
|
|
|
tagtype - None, alias or permission
|
2013-07-12 14:44:49 +02:00
|
|
|
|
2013-11-14 19:31:17 +01:00
|
|
|
Returns a single Tag (or None) if both key and category is given,
|
|
|
|
|
otherwise it will return a list.
|
2013-07-12 11:12:21 +02:00
|
|
|
"""
|
2013-11-14 19:31:17 +01:00
|
|
|
key_cands = Q(db_key__iexact=key.lower().strip()) if key is not None else Q()
|
|
|
|
|
cat_cands = Q(db_category__iexact=category.lower().strip()) if category is not None else Q()
|
2014-02-16 13:19:31 +01:00
|
|
|
tags = self.filter(db_model=model, db_tagtype=tagtype).filter(key_cands & cat_cands)
|
2013-07-12 20:21:52 +02:00
|
|
|
if key and category:
|
2013-07-12 14:44:49 +02:00
|
|
|
return tags[0] if tags else None
|
|
|
|
|
else:
|
|
|
|
|
return list(tags)
|
2013-07-12 11:12:21 +02:00
|
|
|
|
2014-02-16 22:09:35 +01:00
|
|
|
@returns_typeclass_list
|
2014-02-16 13:19:31 +01:00
|
|
|
def get_objs_with_tag(self, key=None, category=None, model="objects.objectdb", tagtype=None):
|
2013-07-12 11:12:21 +02:00
|
|
|
"""
|
|
|
|
|
Search and return all objects of objclass that has tags matching
|
|
|
|
|
the given search criteria.
|
2013-07-12 20:21:52 +02:00
|
|
|
key (string) - the tag identifier
|
2013-07-12 11:12:21 +02:00
|
|
|
category (string) - the tag category
|
2014-02-16 13:19:31 +01:00
|
|
|
model (string) - tag model name. Defaults to "ObjectDB"
|
|
|
|
|
tagtype (string) - None, alias or permission
|
2013-12-02 15:40:02 +01:00
|
|
|
objclass (dbmodel) - the object class to search. If not given, use ObjectDB.
|
2013-07-12 11:12:21 +02:00
|
|
|
"""
|
2014-02-16 13:19:31 +01:00
|
|
|
objclass = ContentType.objects.get_by_natural_key(*model.split(".", 1)).model_class()
|
2013-11-14 19:31:17 +01:00
|
|
|
key_cands = Q(db_tags__db_key__iexact=key.lower().strip()) if key is not None else Q()
|
|
|
|
|
cat_cands = Q(db_tags__db_category__iexact=category.lower().strip()) if category is not None else Q()
|
2014-02-16 22:22:18 +01:00
|
|
|
tag_crit = Q(db_tags__db_model=model, db_tags__db_tagtype=tagtype)
|
|
|
|
|
return objclass.objects.filter(tag_crit & key_cands & cat_cands)
|
2013-07-12 11:12:21 +02:00
|
|
|
|
2014-02-16 13:19:31 +01:00
|
|
|
def create_tag(self, key=None, category=None, data=None, model="objects.objectdb", tagtype=None):
|
2013-07-12 11:12:21 +02:00
|
|
|
"""
|
|
|
|
|
Create a tag. This makes sure the create case-insensitive tags.
|
2014-02-16 13:19:31 +01:00
|
|
|
Note that if the exact same tag configuration (key+category+model+tagtype)
|
2013-07-12 11:12:21 +02:00
|
|
|
exists, it will be re-used. A data keyword will overwrite existing
|
|
|
|
|
data on a tag (it is not part of what makes the tag unique).
|
|
|
|
|
|
|
|
|
|
"""
|
2013-11-14 19:31:17 +01:00
|
|
|
data = str(data) if data is not None else None
|
2013-07-12 11:12:21 +02:00
|
|
|
|
2014-02-16 13:19:31 +01:00
|
|
|
tag = self.get_tag(key=key, category=category, model=model, tagtype=tagtype)
|
2013-11-14 19:31:17 +01:00
|
|
|
if tag and data is not None:
|
2013-07-12 11:12:21 +02:00
|
|
|
tag.db_data = data
|
|
|
|
|
tag.save()
|
|
|
|
|
elif not tag:
|
2013-11-14 19:31:17 +01:00
|
|
|
tag = self.create(db_key=key.lower().strip() if key is not None else None,
|
2014-02-16 13:19:31 +01:00
|
|
|
db_category=category.lower().strip() if category and key is not None else None,
|
|
|
|
|
db_data=str(data) if data is not None else None,
|
|
|
|
|
db_model=model,
|
|
|
|
|
db_tagtype=tagtype)
|
2013-07-12 11:12:21 +02:00
|
|
|
tag.save()
|
2013-08-24 23:57:44 +02:00
|
|
|
return make_iter(tag)[0]
|
2013-07-08 18:13:21 +02:00
|
|
|
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2010-10-31 08:10:02 +00:00
|
|
|
|
|
|
|
|
#class TypedObjectManager(idmap.CachingManager):
|
|
|
|
|
#class TypedObjectManager(models.Manager):
|
|
|
|
|
class TypedObjectManager(idmapper.manager.SharedMemoryManager):
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2012-03-30 23:47:22 +02:00
|
|
|
Common ObjectManager for all dbobjects.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
|
2014-07-06 16:03:27 +02:00
|
|
|
# Attribute manager methods
|
|
|
|
|
|
|
|
|
|
# Tag manager methods
|
|
|
|
|
|
|
|
|
|
def get_tag(self, key=None, category=None, obj=None, tagtype=None):
|
|
|
|
|
"""
|
|
|
|
|
Return Tag objects by key, by category, by object or
|
|
|
|
|
with a combination of those criteria.
|
|
|
|
|
|
|
|
|
|
tagtype - one of None (normal tags), "alias" or "permission"
|
|
|
|
|
"""
|
|
|
|
|
query = [("tag__db_tagtype", tagtype)]
|
|
|
|
|
if obj:
|
|
|
|
|
query.append(("%s__id" % self.model.__name__.lower(), obj.id))
|
|
|
|
|
if key:
|
|
|
|
|
query.append(("tag__db_key", key))
|
|
|
|
|
if category:
|
|
|
|
|
query.append(("tag__db_category", category))
|
|
|
|
|
return self.model.db_tags.through.objects.filter(**dict(query))
|
|
|
|
|
|
|
|
|
|
def get_permission(self, key=None, category=None, obj=None):
|
|
|
|
|
return self.get_tag(key=key, category=category, obj=obj, tagtype="permission")
|
|
|
|
|
|
|
|
|
|
def get_alias(self, key=None, category=None, obj=None):
|
|
|
|
|
return self.get_tag(key=key, category=category, obj=obj, tagtype="alias")
|
|
|
|
|
|
|
|
|
|
@returns_typeclass
|
|
|
|
|
def get_by_tag(self, key=None, category=None, tagtype=None):
|
|
|
|
|
"""
|
|
|
|
|
Return objects having tags with a given key or category or
|
|
|
|
|
combination of the two.
|
|
|
|
|
|
|
|
|
|
tagtype = None, alias or permission
|
|
|
|
|
"""
|
|
|
|
|
query = [("db_tags__db_tagtype", tagtype)]
|
|
|
|
|
if key:
|
|
|
|
|
query.append(("db_tags__db_key", key))
|
|
|
|
|
if category:
|
|
|
|
|
query.append(("db_tags__db_category", category))
|
|
|
|
|
return self.filter(**dict(query))
|
|
|
|
|
|
|
|
|
|
def get_by_permission(self, key=None, category=None):
|
|
|
|
|
return self.get_by_tag(key=key, category=category, tagtype="permission")
|
|
|
|
|
|
|
|
|
|
def get_by_alias(self, key=None, category=None):
|
|
|
|
|
return self.get_by_tag(key=key, category=category, tagtype="alias")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# object-manager methods
|
|
|
|
|
|
2012-10-14 15:45:21 +02:00
|
|
|
def dbref(self, dbref, reqhash=True):
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
Valid forms of dbref (database reference number)
|
|
|
|
|
are either a string '#N' or an integer N.
|
2012-03-30 23:47:22 +02:00
|
|
|
Output is the integer part.
|
2012-10-14 15:45:21 +02:00
|
|
|
reqhash - require input to be on form "#N" to be
|
|
|
|
|
identified as a dbref
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2012-10-14 15:45:21 +02:00
|
|
|
if reqhash and not (isinstance(dbref, basestring) and dbref.startswith("#")):
|
|
|
|
|
return None
|
2010-10-30 18:42:37 +00:00
|
|
|
if isinstance(dbref, basestring):
|
2010-08-29 18:46:58 +00:00
|
|
|
dbref = dbref.lstrip('#')
|
|
|
|
|
try:
|
2012-08-18 23:35:11 +02:00
|
|
|
if int(dbref) < 0:
|
2012-03-30 23:47:22 +02:00
|
|
|
return None
|
2010-08-29 18:46:58 +00:00
|
|
|
except Exception:
|
|
|
|
|
return None
|
|
|
|
|
return dbref
|
2012-03-29 20:30:35 +02:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
@returns_typeclass
|
2012-08-22 16:15:52 +02:00
|
|
|
def get_id(self, dbref):
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2012-08-22 16:15:52 +02:00
|
|
|
Find object with given dbref
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2012-10-14 15:45:21 +02:00
|
|
|
dbref = self.dbref(dbref, reqhash=False)
|
2012-08-22 16:15:52 +02:00
|
|
|
try:
|
|
|
|
|
return self.get(id=dbref)
|
|
|
|
|
except self.model.DoesNotExist:
|
|
|
|
|
pass
|
2010-08-29 18:46:58 +00:00
|
|
|
return None
|
|
|
|
|
|
2012-08-22 16:15:52 +02:00
|
|
|
def dbref_search(self, dbref):
|
|
|
|
|
"""
|
|
|
|
|
Alias to get_id
|
|
|
|
|
"""
|
|
|
|
|
return self.get_id(dbref)
|
|
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
@returns_typeclass_list
|
|
|
|
|
def get_dbref_range(self, min_dbref=None, max_dbref=None):
|
|
|
|
|
"""
|
|
|
|
|
Return all objects inside and including the
|
|
|
|
|
given boundaries.
|
|
|
|
|
"""
|
2013-07-27 04:25:01 -04:00
|
|
|
retval = super(TypedObjectManager, self).all()
|
2013-11-14 19:31:17 +01:00
|
|
|
if min_dbref is not None:
|
2013-07-27 04:25:01 -04:00
|
|
|
retval = retval.filter(id__gte=self.dbref(min_dbref, reqhash=False))
|
2013-11-14 19:31:17 +01:00
|
|
|
if max_dbref is not None:
|
2013-07-27 04:25:01 -04:00
|
|
|
retval = retval.filter(id__lte=self.dbref(max_dbref, reqhash=False))
|
|
|
|
|
return retval
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
def object_totals(self):
|
|
|
|
|
"""
|
|
|
|
|
Returns a dictionary with all the typeclasses active in-game
|
|
|
|
|
as well as the number of such objects defined (i.e. the number
|
2012-03-30 23:47:22 +02:00
|
|
|
of database object having that typeclass set on themselves).
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
dbtotals = {}
|
2011-04-08 23:10:04 +00:00
|
|
|
typeclass_paths = set(self.values_list('db_typeclass_path', flat=True))
|
2012-03-30 23:47:22 +02:00
|
|
|
for typeclass_path in typeclass_paths:
|
2010-08-29 18:46:58 +00:00
|
|
|
dbtotals[typeclass_path] = \
|
|
|
|
|
self.filter(db_typeclass_path=typeclass_path).count()
|
2012-03-30 23:47:22 +02:00
|
|
|
return dbtotals
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
@returns_typeclass_list
|
2014-04-21 15:18:13 +02:00
|
|
|
def typeclass_search(self, typeclass, include_children=False, include_parents=False):
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2014-04-21 15:18:13 +02:00
|
|
|
Searches through all objects returning those which has a
|
|
|
|
|
certain typeclass. If location is set, limit search to objects
|
|
|
|
|
in that location.
|
|
|
|
|
|
|
|
|
|
typeclass - a typeclass class or a python path to a typeclass
|
|
|
|
|
include_children - return objects with given typeclass and all
|
|
|
|
|
children inheriting from this typeclass.
|
|
|
|
|
include_parents - return objects with given typeclass and all
|
|
|
|
|
parents to this typeclass
|
|
|
|
|
The include_children/parents keywords are mutually exclusive.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2014-04-21 15:18:13 +02:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
if callable(typeclass):
|
|
|
|
|
cls = typeclass.__class__
|
|
|
|
|
typeclass = "%s.%s" % (cls.__module__, cls.__name__)
|
2014-04-21 15:18:13 +02:00
|
|
|
elif not isinstance(typeclass, basestring) and hasattr(typeclass, "path"):
|
|
|
|
|
typeclass = typeclass.path
|
|
|
|
|
|
|
|
|
|
# query objects of exact typeclass
|
|
|
|
|
query = Q(db_typeclass_path__exact=typeclass)
|
|
|
|
|
|
|
|
|
|
if include_children:
|
|
|
|
|
# build requests for child typeclass objects
|
|
|
|
|
clsmodule, clsname = typeclass.rsplit(".", 1)
|
|
|
|
|
cls = variable_from_module(clsmodule, clsname)
|
|
|
|
|
subclasses = cls.__subclasses__()
|
|
|
|
|
if subclasses:
|
|
|
|
|
for child in (child for child in subclasses if hasattr(child, "path")):
|
|
|
|
|
query = query | Q(db_typeclass_path__exact=child.path)
|
|
|
|
|
elif include_parents:
|
|
|
|
|
# build requests for parent typeclass objects
|
|
|
|
|
clsmodule, clsname = typeclass.rsplit(".", 1)
|
|
|
|
|
cls = variable_from_module(clsmodule, clsname)
|
|
|
|
|
parents = cls.__mro__
|
|
|
|
|
if parents:
|
|
|
|
|
for parent in (parent for parent in parents if hasattr(parent, "path")):
|
|
|
|
|
query = query | Q(db_typeclass_path__exact=parent.path)
|
|
|
|
|
# actually query the database
|
|
|
|
|
return self.filter(query)
|