Establishing an undirected relationship between two entities is done via the Relationship class. This requires the class of the connected entity as well as the type of the relationship.:

class Person(StructuredNode):
    friends = Relationship('Person', 'FRIEND')

When defining relationships, you may refer to classes in other modules. This avoids cyclic imports:

class Garage(StructuredNode):
    cars = RelationshipTo('transport.models.Car', 'CAR')
    vans = RelationshipTo('.models.Van', 'VAN')


It is possible to (softly) enforce cardinality constraints on your relationships. Remember this needs to be declared on both sides of the relationship definition:

class Person(StructuredNode):
    car = RelationshipTo('Car', 'OWNS', cardinality=One)

class Car(StructuredNode):
    owner = RelationshipFrom('Person', 'OWNS', cardinality=One)

The following cardinality constraints are available:

ZeroOrOne One
ZeroOrMore (default) OneOrMore

If a cardinality constrain is violated by existing data a CardinalityViolation exception is raised.

On attempting to violate a cardinality constrain a AttemptedCardinalityViolation is raised.


Neomodel uses relationship models to define the properties stored on relations:

class FriendRel(StructuredRel):
    since = DateTimeProperty(
    met = StringProperty()

class Person(StructuredNode):
    name = StringProperty()
    friends = RelationshipTo('Person', 'FRIEND', model=FriendRel)

rel = jim.friends.connect(bob)
rel.since # datetime object

The data to populate these properties when establishing a connection can be supplied to the connect method:

rel = jim.friends.connect(bob,
                          {'since': yesterday, 'met': 'Paris'})

print(rel.start_node().name) # jim
print(rel.end_node().name) # bob

rel.met = "Amsterdam"

You can retrieve relationships between two nodes using the ‘relationship’ method. This is only available for relationships with a defined relationship model:

rel = jim.friends.relationship(bob)

Relationship Uniqueness

By default neomodel applies only one relationship instance between two node instances and this is achieved via use of CREATE UNIQUE.

Relationships and Inheritance

Neomodel is capable of understanding and resolving inheritance relationships properly.

The following model establishes a BasePerson that can be friends_with any class derived from BasePerson. Two concrete classes of BasePerson (TechnicalPerson and PilotPerson) are further defined.

class PersonalRelationship(neomodel.StructuredRel):
    A very simple relationship between two BasePersons that simply
    records the date at which an acquaintance was established.
    on_date = neomodel.DateProperty(default_now = True)

class BasePerson(neomodel.StructuredNode):
    Base class for defining some basic sort of an actor in a system.

    The base actor is defined by its name and a `friends_with`
    name = neomodel.StringProperty(required = True, unique_index = True)
    friends_with = neomodel.RelationshipTo("BasePerson", "FRIENDS_WITH", model = PersonalRelationship)

class TechnicalPerson(BasePerson):
    A Technical person specialises BasePerson by adding their
    expertise = neomodel.StringProperty(required = True)

class PilotPerson(BasePerson):
    A pilot person specialises BasePerson by adding the type of
    airplane they can operate.
    airplane = neomodel.StringProperty(required = True)

This means that either of these concrete objects can appear at the end of a friends_with relationship and be instantiated to the right object.

Here is a minimal example to demonstrate that:

# Create some technical persons
A = TechnicalPerson(name = "Grumpy", expertise = "Grumpiness").save()
B = TechnicalPerson(name = "Happy", expertise = "Unicorns"}).save()
C = TechnicalPerson(name = "Sleepy", expertise = "Pillows"}).save()

# Create some Pilot Persons
D = PilotPerson(name = "Porco Rosso", airplane = "Savoia-Marchetti").save()
E = PilotPerson(name = "Jack Dalton", airplane = "Beechcraft Model 18").save()

# TechnicalPersons befriend Technical Persons

# Pilot Persons befriend Pilot Persons

# Technical Persons befriend Pilot Persons

for some_friend in A.friends_with:

This will show two friends connected with node “Grumpy”, one of which is a TechnicalPerson and the other a PilotPerson.

Explicit Traversal

It is possible to specify a node traversal by creating a Traversal object. This will get all Person entities that are directly related to another Person, through all relationships:

definition = dict(node_class=Person, direction=OUTGOING,
                  relation_type=None, model=None)
relations_traversal = Traversal(jim, Person.__label__,
all_jims_relations = relations_traversal.all()

The defintion argument is a mapping with these items:

node_class The class of the traversal target node.
direction match.OUTGOING / match.INCOMING / match.EITHER
relation_type Can be None (for any direction), * for all paths or an explicit name of a relation type (the edge’s label).
model The class of the relation model, None for such without one.