def ClosureTable(model_class, foreign_key=None, referencing_class=None,<EOL>referencing_key=None):
if referencing_class is None:<EOL><INDENT>referencing_class = model_class<EOL><DEDENT>if foreign_key is None:<EOL><INDENT>for field_obj in model_class._meta.refs:<EOL><INDENT>if field_obj.rel_model is model_class:<EOL><INDENT>foreign_key = field_obj<EOL>break<EOL><DEDENT><DEDENT>else:<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT><DEDENT>source_key = model_class._meta.primary_key<EOL>if referencing_key is None:<EOL><INDENT>referencing_key = source_key<EOL><DEDENT>class BaseClosureTable(VirtualModel):<EOL><INDENT>depth = VirtualField(IntegerField)<EOL>id = VirtualField(IntegerField)<EOL>idcolumn = VirtualField(TextField)<EOL>parentcolumn = VirtualField(TextField)<EOL>root = VirtualField(IntegerField)<EOL>tablename = VirtualField(TextField)<EOL>class Meta:<EOL><INDENT>extension_module = '<STR_LIT>'<EOL><DEDENT>@classmethod<EOL>def descendants(cls, node, depth=None, include_node=False):<EOL><INDENT>query = (model_class<EOL>.select(model_class, cls.depth.alias('<STR_LIT>'))<EOL>.join(cls, on=(source_key == cls.id))<EOL>.where(cls.root == node)<EOL>.objects())<EOL>if depth is not None:<EOL><INDENT>query = query.where(cls.depth == depth)<EOL><DEDENT>elif not include_node:<EOL><INDENT>query = query.where(cls.depth > <NUM_LIT:0>)<EOL><DEDENT>return query<EOL><DEDENT>@classmethod<EOL>def ancestors(cls, node, depth=None, include_node=False):<EOL><INDENT>query = (model_class<EOL>.select(model_class, cls.depth.alias('<STR_LIT>'))<EOL>.join(cls, on=(source_key == cls.root))<EOL>.where(cls.id == node)<EOL>.objects())<EOL>if depth:<EOL><INDENT>query = query.where(cls.depth == depth)<EOL><DEDENT>elif not include_node:<EOL><INDENT>query = query.where(cls.depth > <NUM_LIT:0>)<EOL><DEDENT>return query<EOL><DEDENT>@classmethod<EOL>def siblings(cls, node, include_node=False):<EOL><INDENT>if referencing_class is model_class:<EOL><INDENT>fk_value = node.__data__.get(foreign_key.name)<EOL>query = model_class.select().where(foreign_key == fk_value)<EOL><DEDENT>else:<EOL><INDENT>siblings = (referencing_class<EOL>.select(referencing_key)<EOL>.join(cls, on=(foreign_key == cls.root))<EOL>.where((cls.id == node) & (cls.depth == <NUM_LIT:1>)))<EOL>query = (model_class<EOL>.select()<EOL>.where(source_key << siblings)<EOL>.objects())<EOL><DEDENT>if not include_node:<EOL><INDENT>query = query.where(source_key != node)<EOL><DEDENT>return query<EOL><DEDENT><DEDENT>class Meta:<EOL><INDENT>database = referencing_class._meta.database<EOL>options = {<EOL>'<STR_LIT>': referencing_class._meta.table_name,<EOL>'<STR_LIT>': referencing_key.column_name,<EOL>'<STR_LIT>': foreign_key.column_name}<EOL>primary_key = False<EOL><DEDENT>name = '<STR_LIT>' % model_class.__name__<EOL>return type(name, (BaseClosureTable,), {'<STR_LIT:Meta>': Meta})<EOL>
Model factory for the transitive closure extension.