I had essentially the same question. I was unable to find an answer and tried to come up with a solution to this using both py2neo and neomodel.
Just a Beginner
It is important to note that I am definitely not answering this as an expert in either one of these libraries but rather as someone trying to evaluate what might be the best one to start a simple project with.
End Result
The end result is that I found a workaround in py2neo that seems to work. I also got a result in neomodel that I was even happier with. I ended up a little frustrated by both libraries but found neomodel the more intuitive to a newcomer.
An Asset Label is the Answer Right?
I thought that the answer would be to create an "Asset" label and add this label to House and Car and create the [:OWNS] relationship between Person and Asset. Easy right? Nope, apparently not. There might be a straightforward answer but I was unable to find it. The only solution that I got to work in py2neo was to drop down to the lower-level (not OGM) part of the library.
Here's what I did in py2neo:
class Person(GraphObject):
name = Property()
class Car(GraphObject):
name = Property()
model = Property()
asset = Label("Asset")
class House(GraphObject):
name = Property()
city = Property()
asset = Label("Asset")
g = graph
# Create Pete
p = Person()
p.name = "Pete"
g.push(p)
# Create Ferrari
c = Car()
c.name = "Ferrari"
c.asset = True
g.push(c)
# Create House
h = House()
h.name = "White House"
h.city = "New York"
h.asset = True
g.push(h)
# Drop down a level and grab the actual nodes
pn = p.__ogm__.node
cn = c.__ogm__.node
# Pete OWNS Ferrari (lower level py2neo)
ap = Relationship(pn, "OWNS", cn)
g.create(ap)
# Pete OWNS House (lower level py2neo)
hn = h.__ogm__.node
ah = Relationship(pn, "OWNS", hn)
g.create(ah)
# Grab & Print
query = """MATCH (a:Person {name:'Pete'})-[:OWNS]->(n)
RETURN labels(n) as labels, n.name as name"""
data = g.data(query)
for asset in data:
print(asset)
This results in:
{'name': 'White House', 'labels': ['House', 'Asset']}
{'name': 'Ferrari', 'labels': ['Car', 'Asset']}
Neomodel Version
py2neo seems to do some clever tricks with the class names to do its magic and the library seems to exclude Labels from this magic. (I hope I am wrong about this but as I said, I could not solve it). I decided to try neomodel.
class Person(StructuredNode):
name = StringProperty(unique_index=True)
owns = RelationshipTo('Asset', 'OWNS')
likes = RelationshipTo('Car', "LIKES")
class Asset(StructuredNode):
__abstract_node__ = True
__label__ = "Asset"
name = StringProperty(unique_index=True)
class Car(Asset):
pass
class House(Asset):
city = StringProperty()
# Create Person, Car & House
pete = Person(name='Pete').save()
car = Car(name="Ferrari").save()
house = House(name="White House", city="Washington DC").save()
#Pete Likes Car
pete.likes.connect(car)
# Pete owns a House and Car
pete.owns.connect(house)
pete.owns.connect(car)
After these objects are created they are relatively simple to work with:
for l in pete.likes.all():
print(l)
Result:
{'name': 'Ferrari', 'id': 385}
With the "abstract" relationship the result is an object of that type, in this case Asset.
for n in pete.owns.all():
print(n)
print(type(n))
Result:
{'id': 389}
<class '__main__.Asset'>
There seems to be a way to "inflate" these objects to the desired type but I gave up trying to figure that out in favor of just using Cypher. (Would appreciate some help understanding this...)
Dropping down to the Cypher level, we get exactly what we want:
query = "MATCH (a:Person {name:'Pete'})-[:OWNS]->(n) RETURN n"
results, meta = db.cypher_query(query)
for n in results:
print(n)
Result:
[<Node id=388 labels={'Asset', 'Car'} properties={'name': 'Ferrari'}>]
[<Node id=389 labels={'Asset', 'House'} properties={'city': 'Washington DC', 'name': 'White House'}>]
Conclusion
The concept of Labels is very intuitive for a lot of the problems I would like to solve. I found py2neo's treatment of Labels confusing. Your workaround might be to drop down to the "lower-level" of py2neo. I personally thought the neomodel syntax was more friendly and suggest checking it out. HTH.
Car
was printed out. – ham