/search.css" rel="stylesheet" type="text/css"/> /search.js">
00001 """ 00002 Take self-referential many-to-many for a spin 00003 http://www.sqlalchemy.org/docs/orm/relationships.html#self-referential-many-to-many-relationship 00004 00005 00006 SRMM vs SR1M 00007 ~~~~~~~~~~~~~ 00008 00009 Self referential one-to-many example ... familiar tree structure 00010 * unix "Directory" has single parent "Directory", and multiple child "Directory" 00011 00012 Self referential many-to-many example for "People" 00013 * some have friends (symmetrical relationship) 00014 * some have idols (asymmetrical relationship) 00015 * others have stalkers (asymmetrical relationship) 00016 00017 subsets and supersets with all manner of possible containments 00018 00019 00020 .. code-block: ipython 00021 00022 00023 n [2]: from NonDbi import Node 00024 00025 In [3]: n = Node("color") 00026 00027 In [5]: n. 00028 n.__class__ n.__format__ n.__mapper__ n.__reduce_ex__ n.__str__ n.__weakref__ n.id n.right_nodes 00029 n.__delattr__ n.__getattribute__ n.__module__ n.__repr__ n.__subclasshook__ n._decl_class_registry n.label 00030 n.__dict__ n.__hash__ n.__new__ n.__setattr__ n.__table__ n._sa_class_manager n.left_nodes 00031 n.__doc__ n.__init__ n.__reduce__ n.__sizeof__ n.__tablename__ n._sa_instance_state n.metadata 00032 00033 In [5]: n.left_nodes 00034 n.left_nodes 00035 00036 In [5]: n.left_nodes 00037 Out[5]: [] 00038 00039 In [6]: n.left_nodes.append(Node("red")) 00040 00041 In [7]: n.left_nodes.append(Node("green")) 00042 00043 In [8]: n.left_nodes.append(Node("blue")) 00044 00045 In [9]: n.left_nodes 00046 Out[9]: [Node('red'), Node('green'), Node('blue')] 00047 00048 In [10]: session 00049 Out[10]: <sqlalchemy.orm.session.Session object at 0x94cdb6c> 00050 00051 In [11]: session.add(n) 00052 00053 In [12]: session.commit() 00054 00055 00056 00057 Note that the colors are not to session individually, they come 00058 via their association:: 00059 00060 mysql> select * from node_to_node ; 00061 +--------------+---------------+ 00062 | left_node_id | right_node_id | 00063 +--------------+---------------+ 00064 | 3 | 2 | 00065 | 4 | 2 | 00066 | 5 | 2 | 00067 +--------------+---------------+ 00068 3 rows in set (0.00 sec) 00069 00070 mysql> select * from node ; 00071 +----+-------+ 00072 | id | label | 00073 +----+-------+ 00074 | 1 | root | 00075 | 2 | color | 00076 | 3 | red | 00077 | 4 | green | 00078 | 5 | blue | 00079 +----+-------+ 00080 5 rows in set (0.00 sec) 00081 00082 00083 00084 00085 Compare with Django recursive M2M to self 00086 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00087 00088 * https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ManyToManyField.symmetrical 00089 00090 Django symetrical m2m to self:: 00091 00092 class Person(models.Model): 00093 friends = models.ManyToManyField("self") 00094 00095 When Django processes this model, it identifies that it has a ManyToManyField on itself, and as a result, 00096 it doesn't add a person_set attribute to the Person class. 00097 Instead, the ManyToManyField is assumed to be symmetrical -- that is, if I am your friend, then you are my friend. 00098 00099 If you do not want symmetry in many-to-many relationships with self, set symmetrical to False. 00100 This will force Django to add the descriptor for the reverse relationship, 00101 allowing ManyToManyField relationships to be non-symmetrical. 00102 00103 Presumably that means can do: 00104 00105 class Person(models.Model): 00106 friends = models.ManyToManyField("self") 00107 idols = models.ManyToManyField("self", symetrical=False ) 00108 00109 00110 00111 00112 """ 00113 from sqlalchemy import Integer, ForeignKey, String, Column, Table 00114 from sqlalchemy.orm import relationship 00115 from meta import Base 00116 00117 node_to_node = Table("node_to_node", Base.metadata, 00118 Column("left_node_id", Integer, ForeignKey("node.id"), primary_key=True), 00119 Column("right_node_id", Integer, ForeignKey("node.id"), primary_key=True) 00120 ) 00121 00122 class Node(Base): 00123 """ 00124 00125 00126 00127 """ 00128 __tablename__ = 'node' 00129 id = Column(Integer, primary_key=True) 00130 label = Column(String(255)) 00131 right_nodes = relationship("Node", 00132 secondary=node_to_node, 00133 primaryjoin=id==node_to_node.c.left_node_id, 00134 secondaryjoin=id==node_to_node.c.right_node_id, 00135 backref="left_nodes" 00136 ) 00137 00138 def __init__(self, label ): 00139 self.label = label 00140 def __repr__(self): 00141 return "Node('%s')" % self.label 00142 00143 00144 00145