### Install Neomodel from GitHub Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/index.md Install the development version of neomodel directly from its GitHub repository. ```bash $ pip install git+git://github.com/neo4j-contrib/neomodel.git@HEAD#egg=neomodel-dev ``` -------------------------------- ### Define Product Node with Full Text Index Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/semantic_indexes.md Example of defining a `Product` node with a `name` property and a `description` property that has a full-text index. The index must be installed using `install_all_labels()`. ```python class Product(StructuredNode): name = StringProperty() description = StringProperty( fulltext_index=FulltextIndex( analyzer="standard-no-stop-words", eventually_consistent=False ) ) ``` -------------------------------- ### Install Twine and Authenticate Source: https://github.com/neo4j-contrib/neomodel/wiki/Making-a-release-to-PyPI Ensure Twine is installed and authenticated with PyPI to upload distribution files. ```bash $ pip install twine ``` -------------------------------- ### Install neomodel from GitHub Source: https://github.com/neo4j-contrib/neomodel/blob/master/README.md Install the latest development version of neomodel directly from its GitHub repository. ```bash pip install git+git://github.com/neo4j-contrib/neomodel.git@HEAD#egg=neomodel-dev ``` -------------------------------- ### Legacy Self-Managed Driver Setup Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/configuration.md Demonstrates how to set up a legacy self-managed driver. Note that only the synchronous driver is supported with this approach. ```python from neo4j import GraphDatabase my_driver = GraphDatabase().driver('bolt://localhost:7687', auth=('neo4j', 'password')) config.DRIVER = my_driver ``` -------------------------------- ### Install neomodel from PyPI Source: https://github.com/neo4j-contrib/neomodel/blob/master/README.md Install the neomodel package using pip. Use the 'source dev' command to install all necessary components within a Python 3 virtual environment. ```bash pip install neomodel ($ source dev # To install all things needed in a Python3 venv) ``` -------------------------------- ### Install Neomodel from PyPI Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/index.md Use pip to install the recommended version of neomodel from the Python Package Index. ```bash $ pip install neomodel ``` -------------------------------- ### Install Dependencies and Run Tests Source: https://github.com/neo4j-contrib/neomodel/blob/master/README.md Install neomodel for development using the provided requirements file and run the test suite with pytest. ```bash pip install -r requirements-dev.txt ``` ```bash pytest ``` -------------------------------- ### Install neomodel with optional dependencies Source: https://github.com/neo4j-contrib/neomodel/blob/master/README.md Install neomodel along with optional dependencies such as Shapely, pandas, and numpy, and the Rust driver extension. ```bash pip install neomodel[extras, rust-driver-ext] ``` -------------------------------- ### Install neomodel with Rust driver extension Source: https://github.com/neo4j-contrib/neomodel/blob/master/README.md Install neomodel with the Rust extension for the Neo4j driver to potentially improve transport speed. ```bash pip install neomodel[rust-driver-ext] ``` -------------------------------- ### Get Last Release Tag Source: https://github.com/neo4j-contrib/neomodel/wiki/Making-a-release-to-PyPI Identify the tag of the most recent release to determine the starting point for changes. ```bash $ git describe --abbrev=0 --tags ``` -------------------------------- ### Full Example: Mixed Query Operations Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/getting_started.md Demonstrates combining filtering, ordering, traversal, subqueries, and transformations in a single asynchronous query. ```python # These are the class definitions used for the query below class HasCourseRel(AsyncStructuredRel): level = StringProperty() start_date = DateTimeProperty() end_date = DateTimeProperty() class Course(AsyncStructuredNode): name = StringProperty() class Building(AsyncStructuredNode): name = StringProperty() class Student(AsyncStructuredNode): name = StringProperty() parents = AsyncRelationshipTo("Student", "HAS_PARENT", model=AsyncStructuredRel) children = AsyncRelationshipFrom("Student", "HAS_PARENT", model=AsyncStructuredRel) lives_in = AsyncRelationshipTo(Building, "LIVES_IN", model=AsyncStructuredRel) courses = AsyncRelationshipTo(Course, "HAS_COURSE", model=HasCourseRel) preferred_course = AsyncRelationshipTo( Course, "HAS_PREFERRED_COURSE", model=AsyncStructuredRel, cardinality=AsyncZeroOrOne, ) # This is the query full_nodeset = ( await Student.nodes.filter(name__istartswith="m", lives_in__name="Eiffel Tower") # Combine filters .order_by("name") .traverse( "parents", Path(value="children__preferred_course", optional=True) ) # Combine traversals .subquery( Student.nodes.traverse("courses") # Root variable student will be auto-injected here .intermediate_transform( {"rel": RelationNameResolver("courses")}, ordering=[ RawCypher("toInteger(split(rel.level, '.')[0])"), RawCypher("toInteger(split(rel.level, '.')[1])"), "rel.end_date", "rel.start_date", ], # Intermediate ordering ) .annotate( latest_course=Last(Collect("rel")), ), ["latest_course"], ) ) # Using async, we need to do 2 await # One is for subquery, the other is for resolve_subgraph ``` -------------------------------- ### Get Latest Code Source: https://github.com/neo4j-contrib/neomodel/wiki/Making-a-release-to-PyPI Fetch the most recent code from the master branch before starting the release process. ```bash $ git checkout master $ git pull ``` -------------------------------- ### Install Neomodel with NumPy Integration Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/cypher.md Install Neomodel with optional NumPy support using pip. This enables returning query results as NumPy ndarrays. ```bash # When installing neomodel pip install neomodel[numpy] # Or separately pip install numpy ``` -------------------------------- ### Install Indexes and Constraints for Entire Schema Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/configuration.md Run `install_all_labels()` to set up indexes and constraints for all models within your loaded Django application. Make sure your application is imported and loaded before execution. ```python import yourapp # make sure your app is loaded from neomodel import install_all_labels install_all_labels() # Output: # Setting up labels and constraints... # Found yourapp.models.User # + Creating unique constraint for name on label User for class yourapp.models.User # ... ``` -------------------------------- ### Node-Class Registry Mapping Example Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/extending.md Illustrates the internal mapping of node labels to their corresponding Python classes within Neomodel's node-class registry. ```default {"BasePerson"} --> class BasePerson {"BasePerson", "TechnicalPerson"} --> class TechnicalPerson {"BasePerson", "PilotPerson"} --> class PilotPerson {"User"} --> class UserClass ``` -------------------------------- ### Install Neomodel with Pandas Integration Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/cypher.md Install Neomodel with optional Pandas support using pip. This enables returning query results as Pandas DataFrames or Series. ```bash # When installing neomodel pip install neomodel[pandas] # Or separately pip install pandas ``` -------------------------------- ### Install Indexes and Constraints for a Single Class Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/configuration.md Use the `install_labels` function from neomodel to automatically create indexes and constraints for a specific class. Ensure the class is defined before calling this function. ```python from neomodel import install_labels install_labels(YourClass) ``` -------------------------------- ### Save and Use Array Property Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/properties.md Example of creating a Person with an array of names and saving it to the database. Elements are deflated to strings before persistence. ```python bob = Person(names=['bob', 'rob', 'robert']).save() ``` -------------------------------- ### Load Configuration from Environment Variables Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/configuration.md Illustrates how neomodel automatically loads configuration from environment variables prefixed with `NEOMODEL_`. This example shows setting database URL, timezone forcing, and connection timeout. ```bash # Set environment variables export NEOMODEL_DATABASE_URL='bolt://neo4j:password@localhost:7687' export NEOMODEL_FORCE_TIMEZONE='true' export NEOMODEL_CONNECTION_TIMEOUT='60.0' # Configuration will be automatically loaded from environment from neomodel import config print(config.DATABASE_URL) # 'bolt://neo4j:password@localhost:7687' print(config.FORCE_TIMEZONE) # True print(config.CONNECTION_TIMEOUT) # 60.0 ``` -------------------------------- ### Async Dunder Methods for Nodes and Relationships Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/getting_started.md Examples of asynchronous equivalents for common dunder methods like __len__, __bool__, __contains__, and __getitem__. ```python # Length dogs_bonanza = await Dog.nodes.get_len() # Sync equivalent - __len__ dogs_bonanza = len(Dog.nodes) # Note that len(Dog.nodes) is more efficient than Dog.nodes.__len__ # Existence assert not await Customer.nodes.filter(email="jim7@aol.com").check_bool() # Sync equivalent - __bool__ assert not Customer.nodes.filter(email="jim7@aol.com") # Also works for check_nonzero => __nonzero__ # Contains assert await Coffee.nodes.check_contains(aCoffeeNode) # Sync equivalent - __contains__ assert aCoffeeNode in Coffee.nodes # Get item assert len(list((await Coffee.nodes)[1:])) == 2 # Sync equivalent - __getitem__ assert len(list(Coffee.nodes[1:])) == 2 ``` -------------------------------- ### Access and Update Neomodel Configuration Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/configuration.md Demonstrates how to get the current neomodel configuration, access specific settings like database URL and timezone forcing, and update them using the `update` method. ```python from neomodel import get_config, set_config, reset_config # Get the current configuration config = get_config() print(config.database_url) print(config.force_timezone) # Update configuration config.update(database_url='bolt://new:url@localhost:7687') # Set a custom configuration from neomodel import NeomodelConfig custom_config = NeomodelConfig( database_url='bolt://custom:url@localhost:7687', force_timezone=True ) set_config(custom_config) # Reset to defaults (loads from environment variables or defaults) reset_config() ``` -------------------------------- ### Legacy Configuration with Deprecation Warning Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/configuration.md Shows how setting the legacy `DATABASE_URL` triggers a deprecation warning, guiding users to the modern configuration API. ```python import warnings from neomodel import config # This will show a deprecation warning config.DATABASE_URL = 'bolt://neo4j:password@localhost:7687' # DeprecationWarning: Setting config.DATABASE_URL is deprecated and will be removed in a future version. # Use the modern configuration API instead: # from neomodel import get_config; config = get_config(); config.database_url = value ``` -------------------------------- ### Get or Create Node with Specific Properties Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/batch.md Demonstrates retrieving or creating a node using specific properties. If the node exists, it's fetched; otherwise, it's created with the provided properties. Subsequent updates only affect newly created nodes. ```python class Person(StructuredNode): name = StringProperty(required=True) age = IntegerProperty() node = await Person.get_or_create({"name": "Tania", "age": 20}) assert node[0].name == "Tania" assert node[0].age == 20 node = await MultiRequiredPropNode.get_or_create({"name": "Tania", "age": 30}) assert node[0].name == "Tania" assert node[0].age == 20 # Tania was fetched and not created, age is still 20 ``` -------------------------------- ### Batch Get or Create Nodes Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/batch.md Atomically retrieve or create multiple nodes in a single operation. Required and unique properties are used for matching existing nodes; other properties are used only for creation. ```python people = Person.get_or_create( {'name': 'Tim'}, # created {'name': 'Bob'}, # created ) people_with_jill = Person.get_or_create( {'name': 'Tim'}, # fetched {'name': 'Bob'}, # fetched {'name': 'Jill'}, # created ) # are same nodes assert people[0] == people_with_jill[0] assert people[1] == people_with_jill[1] ``` -------------------------------- ### Enable Slow Query Logging Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/configuration.md Configure `config.slow_queries` with a time threshold in seconds to log queries exceeding this duration. For example, setting it to `1.0` logs queries taking longer than 1 second. ```python config.slow_queries = 1.0 # Log queries taking more than 1 second ``` -------------------------------- ### Post Creation Hook Example Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/hooks.md Defines a `post_create` hook on a `StructuredNode` subclass. This hook is executed after a new node is created. Note that this hook is not called by `get_or_create` and `create_or_update` methods. ```python class Person(StructuredNode): def post_create(self): email_welcome_message(self) ``` -------------------------------- ### Retrieve Nodes with Neomodel Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/getting_started.md Shows how to retrieve nodes using the .nodes property. Supports fetching all nodes, getting a specific node by criteria, or handling cases where a node might not exist. ```python # Return all nodes all_nodes = Person.nodes.all() # Returns Person by Person.name=='Jim' or raises neomodel.DoesNotExist if no match jim = Person.nodes.get(name='Jim') # Will return None unless "bob" exists someone = Person.nodes.get_or_none(name='bob') # Will return the first Person node with the name bob. This raises neomodel.DoesNotExist if there's no match. someone = Person.nodes.first(name='bob') # Will return the first Person node with the name bob or None if there's no match someone = Person.nodes.first_or_none(name='bob') # Return set of nodes people = Person.nodes.filter(age__gt=3) ``` -------------------------------- ### Get or Create Node Based on Relationship Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/batch.md When a `relationship` parameter is passed to `get_or_create()`, node matching is performed based on that relationship context, making the relationship itself a key for matching. ```python class Dog(StructuredNode): name = StringProperty(required=True) owner = RelationshipTo('Person', 'owner') class Person(StructuredNode): name = StringProperty(unique_index=True) pets = RelationshipFrom('Dog', 'owner') bob = Person.get_or_create({"name": "Bob"})[0] bobs_gizmo = Dog.get_or_create({"name": "Gizmo"}, relationship=bob.pets) tim = Person.get_or_create({"name": "Tim"})[0] tims_gizmo = Dog.get_or_create({"name": "Gizmo"}, relationship=tim.pets) # not the same gizmo assert bobs_gizmo[0] != tims_gizmo[0] ``` -------------------------------- ### Configure Neomodel Database Connection Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/getting_started.md Set the database connection URL early in your application. For Django, use the `settings.py` file. Ensure your Neo4j server's default password is changed if it's a new installation. ```python from neomodel import get_config config = get_config() config.database_url = 'bolt://neo4j:password@localhost:7687' # default ``` -------------------------------- ### Connect Nodes with Relationship Properties Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/relationships.md When connecting nodes, data for relationship properties can be supplied to the connect method. The start and end nodes of the relationship can be accessed via start_node() and end_node(). ```python rel = jim.friends.connect(bob) rel.since # datetime object rel = jim.friends.connect(bob, {'since': yesterday, 'met': 'Paris'}) print(rel.start_node().name) # jim print(rel.end_node().name) # bob rel.met = "Amsterdam" rel.save() ``` -------------------------------- ### Handle Invalid Optional Property Value Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/properties.md Shows an example where saving an entity fails due to an invalid value for an optional property ('email'). An empty string is not a valid email format. ```python some_person = Person(full_name="Thomas Edison", email="").save() ``` -------------------------------- ### Get or Create with Custom Merge Keys Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/batch.md Utilize the `merge_by` parameter in `get_or_create()` to define custom criteria for matching nodes, allowing merging based on specific properties like 'email' or 'username' instead of the default unique indexes. ```python class User(StructuredNode): username = StringProperty(required=True, unique_index=True) email = StringProperty(required=True, unique_index=True) full_name = StringProperty() age = IntegerProperty() # Default behavior (merge by username + email) users = User.get_or_create({ 'username': 'johndoe', 'email': 'john@example.com', 'age': 30 }) # Custom merge by email only users = User.get_or_create({ 'username': 'johndoe', 'email': 'john@example.com', 'age': 31 }, merge_by={'keys': ['email']}) # Custom merge by username only users = User.get_or_create({ 'username': 'johndoe', 'email': 'john.doe@newcompany.com', 'age': 32 }, merge_by={'label': 'User', 'keys': ['username']}) ``` -------------------------------- ### Define Node Entities and Relationships Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/getting_started.md Define Python classes that map to Neo4j nodes and relationships using `StructuredNode`, `StringProperty`, `IntegerProperty`, `UniqueIdProperty`, and `RelationshipTo`. This example shows definitions for Country, City, and Person nodes with relationships. ```python from neomodel import ( get_config, StructuredNode, StringProperty, IntegerProperty, UniqueIdProperty, RelationshipTo ) config = get_config() config.database_url = 'bolt://neo4j_username:neo4j_password@localhost:7687' class Country(StructuredNode): code = StringProperty(unique_index=True, required=True) class City(StructuredNode): name = StringProperty(required=True) country = RelationshipTo(Country, 'FROM_COUNTRY') class Person(StructuredNode): uid = UniqueIdProperty() name = StringProperty(unique_index=True) age = IntegerProperty(index=True, default=0) # traverse outgoing IS_FROM relations, inflate to Country objects country = RelationshipTo(Country, 'IS_FROM') # traverse outgoing LIVES_IN relations, inflate to City objects city = RelationshipTo(City, 'LIVES_IN') ``` -------------------------------- ### Create and Upload Distributions Source: https://github.com/neo4j-contrib/neomodel/wiki/Making-a-release-to-PyPI Clean the distribution directory, build the source distribution, and upload the files to PyPI using Twine. ```bash $ rm -rf dist/* $ python setup.py sdist $ twine upload dist/* ``` -------------------------------- ### Migrating Legacy to Modern Configuration Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/configuration.md Compares the legacy configuration syntax with the modern equivalent for several common settings, illustrating the migration process. ```python from neomodel import config config.DATABASE_URL = 'bolt://neo4j:password@localhost:7687' config.FORCE_TIMEZONE = True config.MAX_CONNECTION_POOL_SIZE = 50 ``` ```python from neomodel import get_config config = get_config() config.database_url = 'bolt://neo4j:password@localhost:7687' config.force_timezone = True config.max_connection_pool_size = 50 ``` -------------------------------- ### Load Configuration from Environment Variables Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/configuration.md Illustrates the recommended approach for protecting credentials by setting the database URL via environment variables, which neomodel automatically loads. ```bash # Set environment variables export NEOMODEL_DATABASE_URL='bolt://neo4j:password@localhost:7687' # Configuration automatically loads from environment from neomodel import get_config config = get_config() ``` -------------------------------- ### Generated Cypher Query Example Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/getting_started.md This is an example of a Cypher query generated by Neomodel's subgraph resolution. It includes complex MATCH, OPTIONAL MATCH, WHERE clauses, and CALL subqueries. ```cypher MATCH (student:Student)-[r1:`HAS_PARENT`]->(student_parents:Student) MATCH (student)-[r4:`LIVES_IN`]->(building_lives_in:Building) OPTIONAL MATCH (student)<-[r2:`HAS_PARENT`]-(student_children:Student)-[r3:`HAS_PREFERRED_COURSE`]->(course_children__preferred_course:Course) WITH * # building_lives_in_name_1 = "Eiffel Tower" # student_name_1 = "(?i)m.*" WHERE building_lives_in.name = $building_lives_in_name_1 AND student.name =~ $student_name_1 CALL { WITH student MATCH (student)-[r1:`HAS_COURSE`]->(course_courses:Course) WITH r1 AS rel ORDER BY toInteger(split(rel.level, '.')[0]),toInteger(split(rel.level, '.')[1]),rel.end_date,rel.start_date RETURN last(collect(rel)) AS latest_course } RETURN latest_course, student, student_parents, r1, student_children, r2, course_children__preferred_course, r3, building_lives_in, r4, collect(DISTINCT student_children) AS children, collect(DISTINCT course_children__preferred_course) AS children_preferred_course ORDER BY student.name ``` -------------------------------- ### Set Database Name with Legacy Configuration Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/configuration.md Illustrates two ways to specify the database name using the legacy configuration approach: by including it in the URL or using a separate config option. ```python # Using the URL only config.DATABASE_URL = 'bolt://neo4j:neo4j@localhost:7687/mydb' # Using config option config.DATABASE_URL = 'bolt://neo4j:neo4j@localhost:7687' config.DATABASE_NAME = 'mydb' ``` -------------------------------- ### Basic Transaction with Context Manager Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/transactions.md Use a context manager for basic transaction handling. Ensure imports are present. ```python from neomodel import db with db.transaction: Person(name='Bob').save() ``` -------------------------------- ### Access Relationship Endpoints Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/relationships.md Access the start and end nodes of a resolved relationship object. This is possible because resolve_objects=True instantiates the relationship to its proper model. ```python u = Z[0][0][0].start_node() v = Z[0][0][0].end_node() ``` -------------------------------- ### Define Relationship Model for Traversal Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/traversal.md When `include_rels_in_return=True` (default), relationships traversed must have a model defined. This example shows how to define a default `StructuredRel` for a relationship. ```python class Person(StructuredNode): country = RelationshipTo(Country, 'IS_FROM', model=StructuredRel) ``` -------------------------------- ### Resolve Subgraph for Object-Oriented Results Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/traversal.md Use `resolve_subgraph` with `fetch_relations` to get a list of subgraphs where each node contains its relations and neighbors, instead of a list of tuples. ```python results = Coffee.nodes.fetch_relations('suppliers__country').resolve_subgraph().all() ``` -------------------------------- ### Update Version Number in setup.py Source: https://github.com/neo4j-contrib/neomodel/wiki/Making-a-release-to-PyPI Modify the version number in the setup.py file to reflect the new release version. ```bash $ vi setup.py ``` -------------------------------- ### Convert Cypher Query Results to NumPy ndarray Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/cypher.md Use `to_ndarray` from `neomodel.integration.numpy` to convert Cypher query results into a NumPy ndarray. Ensure NumPy is installed. ```python from neomodel import db from neomodel.integration.numpy import to_ndarray array = to_ndarray(db.cypher_query("MATCH (a:Person) RETURN a.name AS name, a.born AS born")) ``` -------------------------------- ### Apply Schema Definitions to Neo4j Database Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/schema_management.md Use the `neomodel_install_labels` script to automatically create indexes and constraints defined in your neomodel classes on your Neo4j database. It's recommended to run this after schema changes. The `--db` argument can be omitted to use the `NEO4J_BOLT_URL` environment variable. ```bash $ neomodel_install_labels yourapp.py someapp.models --db bolt://neo4j_username:neo4j_password@localhost:7687 ``` -------------------------------- ### Legacy Configuration Settings Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/configuration.md Shows various configuration options using the legacy uppercase attribute approach. This method is deprecated and will trigger warnings. ```python from neomodel import config # Legacy approach (still works but shows deprecation warnings) config.DATABASE_URL = 'bolt://neo4j:neo4j@localhost:7687' config.MAX_CONNECTION_POOL_SIZE = 100 config.CONNECTION_ACQUISITION_TIMEOUT = 60.0 config.CONNECTION_TIMEOUT = 30.0 config.ENCRYPTED = False config.KEEP_ALIVE = True config.MAX_CONNECTION_LIFETIME = 3600 config.MAX_TRANSACTION_RETRY_TIME = 30.0 config.RESOLVER = None config.TRUST = neo4j.TRUST_SYSTEM_CA_SIGNED_CERTIFICATES config.USER_AGENT = 'neomodel/v5.5.1' ``` -------------------------------- ### Define Node Models for Traversal Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/traversal.md These models define the structure of nodes and relationships used in traversal examples. Ensure relationships have a defined model if `include_rels_in_return` is true. ```python class Country(StructuredNode): country_code = StringProperty(unique_index=True) name = StringProperty() class Supplier(StructuredNode): name = StringProperty() delivery_cost = IntegerProperty() country = RelationshipTo(Country, 'ESTABLISHED_IN') class Coffee(StructuredNode): name = StringProperty(unique_index=True) price = IntegerProperty() suppliers = RelationshipFrom(Supplier, 'SUPPLIES') ``` -------------------------------- ### Multiple Path Traversal Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/traversal.md Traverse multiple distinct paths from a starting node. This allows for complex queries that gather data from different branches of the graph simultaneously. ```python Coffee.nodes.traverse('suppliers__country', 'pub__city').all() ``` -------------------------------- ### Convert Cypher Query Results to Pandas DataFrame/Series Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/cypher.md Use `to_dataframe` or `to_series` from `neomodel.integration.pandas` to convert Cypher query results into Pandas objects. Ensure Pandas is installed. ```python from neomodel import db from neomodel.integration.pandas import to_dataframe, to_series df = to_dataframe(db.cypher_query("MATCH (a:Person) RETURN a.name AS name, a.born AS born")) series = to_series(db.cypher_query("MATCH (a:Person) RETURN a.name AS name")) ``` -------------------------------- ### Create, Update, and Delete Operations Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/getting_started.md Demonstrates basic CRUD operations and instance management using neomodel's convenience methods. Use .save() for create/update, .delete() to remove, and .refresh() to reload from the database. ```python jim = Person(name='Jim', age=3).save() # Create jim.age = 4 jim.save() # Update, (with validation) jim.delete() jim.refresh() # reload properties from the database jim.element_id # neo4j internal element id ``` -------------------------------- ### Run Tests with Docker Compose Source: https://github.com/neo4j-contrib/neomodel/blob/master/README.md Execute the test suite against multiple Python interpreters and Neo4j versions using Docker Compose. Navigate to the project's root folder before running. ```bash # in the project's root folder: $ sh ./tests-with-docker-compose.sh ``` -------------------------------- ### Define Explicit Node Traversal Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/relationships.md Use Traversal to specify node traversals. This example retrieves all Person entities directly related to another Person through any outgoing relationship. ```python definition = dict(node_class=Person, direction=RelationshipDirection.OUTGOING, relation_type=None, model=None) relations_traversal = Traversal(jim, Person.__label__, definition) all_jims_relations = relations_traversal.all() ``` -------------------------------- ### Transpile Async to Sync Code Source: https://github.com/neo4j-contrib/neomodel/blob/master/README.md Run the 'make-unasync' script to automatically transpile async code to its sync version. Follow with 'isort' and 'black' for code formatting. ```bash bin/make-unasync isort . black . ``` -------------------------------- ### Use String Property Choices Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/properties.md Demonstrates saving a Person with a chosen sex and retrieving the display name using get_sex_display(). ```python tim = Person(sex='M').save() tim.sex # M tim.get_sex_display() # 'Male' ``` -------------------------------- ### Override StructuredNode Constructor Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/extending.md When defining custom constructors for StructuredNode, always call the superclass constructor. This example shows how to initialize an Item node using a Product entity, deriving properties from it. ```python class Item(StructuredNode): name = StringProperty(unique_index=True) uid = StringProperty(unique_index=True) def __init__(self, product=None, *args, **kwargs): if product is not None: self.product = product kwargs["uid"] = 'g.' + str(self.product.pk) kwargs["name"] = self.product.product_name super().__init__(*args, **kwargs) ``` -------------------------------- ### Connect and Manage Relationships Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/getting_started.md Illustrates how to establish, check, and disconnect relationships between nodes. Supports filtering related nodes and accessing relationship properties. ```python germany = Country(code='DE').save() jim.country.connect(germany) berlin = City(name='Berlin').save() berlin.country.connect(germany) jim.city.connect(berlin) if jim.country.is_connected(germany): print("Jim's from Germany") for p in germany.inhabitant.all(): print(p.name) # Jim len(germany.inhabitant) # 1 # Find people called 'Jim' in germany germany.inhabitant.filter(name='Jim') # Find all the people called in germany except 'Jim' germany.inhabitant.exclude(name='Jim') # Remove Jim's country relationship with Germany jim.country.disconnect(germany) usa = Country(code='US').save() jim.country.connect(usa) jim.country.connect(germany) ``` -------------------------------- ### Change Connection with Legacy API Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/configuration.md Shows how to change the database connection using the legacy `db.set_connection` method with a URL. This assumes an auto-managed driver. ```python from neomodel import db # Using URL - auto-managed db.set_connection(url='bolt://neo4j:neo4j@localhost:7687') ``` -------------------------------- ### Using Bookmarks with Context Managers Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/transactions.md Set and extract bookmarks when using neomodel transactions with context managers. Ensure database access occurs after specified transactions are complete. ```python transaction = db.transaction transaction.bookmarks = [bookmark1, bookmark2] with transaction: # All database access happens after completion of the transactions # listed in bookmark1 and bookmark2 bookmark = transaction.last_bookmarks ``` -------------------------------- ### Inspect Changes and Update Changelog Source: https://github.com/neo4j-contrib/neomodel/wiki/Making-a-release-to-PyPI Review the changes made since the last release and update the Changelog file accordingly. Ensure the changelog format is consistent. ```bash $ git log 3.2.9... $ vi Changelog ``` ```plaintext Version 2018-10-04 * Add check for wiping db on test run - Athanasios * Correct function name in doc string - Henry Jordan ``` -------------------------------- ### Set Database URL and Name Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/configuration.md Configure the database connection URL and specify a custom database name for neomodel. This is useful when not using the default database. ```python config.database_url = 'bolt://neo4j:password@localhost:7687' config.database_name = 'mydatabase' ``` -------------------------------- ### Instantiate NeomodelPoint from another NeomodelPoint Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/spatial_properties.md Use the copy constructor to create a new NeomodelPoint with the same coordinates and CRS as an existing one. ```python new_object = neomodel.contrib.spatial_properties.NeomodelPoint(old_object); ``` -------------------------------- ### Node Inheritance with Relationships Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/relationships.md Neomodel supports node inheritance, allowing relationships to be established between derived node types. This example defines a BasePerson with a friends_with relationship and two derived classes, TechnicalPerson and PilotPerson. ```python 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` relationship. """ 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. """ 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) ``` -------------------------------- ### Instantiate Cartesian-3D NeomodelPoint using x, y, z Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/spatial_properties.md Create a Cartesian-3D point by providing x, y, and z components directly. ```python new_object = neomodel.contrib.spatial_properties.NeomodelPoint(x=0.0, y=0.0, z=12.0) ``` -------------------------------- ### Manual Transaction with Bookmarks Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/transactions.md Manually begin, commit, or rollback transactions while managing bookmarks. This approach provides explicit control over the transaction lifecycle and bookmark handling. ```python db.begin(bookmarks=bookmarks) try: new_user = Person(name=username, email=email).save() send_email(new_user) bookmarks = db.commit() except Exception as e: db.rollback() ``` -------------------------------- ### Attempt to instantiate geographical point with x, y, z Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/spatial_properties.md This will raise an exception because geographical points do not have x, y, z components. ```python new_object = neomodel.contrib.spatial_properties.NeomodelPoint(x=0.0, y=0.0, z=12.0, crs='wgs-84-3d') ``` -------------------------------- ### Create Node with PointProperty Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/spatial_properties.md Create a Neomodel Node and assign a NeomodelPoint to its PointProperty, ensuring the CRS matches. ```python my_entity = SomeEntity(location=neomodel.contrib.spatial_properties.NeomodelPoint((0.0,0.0), crs='wgs-84')).save() ``` -------------------------------- ### Handling Class Redefinition with __allow_reload__ Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/extending.md Demonstrates how to override the default `NodeClassAlreadyDefined` exception behavior by setting `__allow_reload__ = True` on a class, which will issue a warning instead. ```default import neomodel class BasePerson(neomodel.StructuredNode): pass class TechnicalPerson(BasePerson): pass class PilotPerson(BasePerson): pass def some_function(): class PilotPerson(BasePerson): __allow_reload__ = True pass ``` -------------------------------- ### Update Read the Docs Source: https://github.com/neo4j-contrib/neomodel/wiki/Making-a-release-to-PyPI After a successful release to PyPI, update the documentation on Read the Docs with the latest version. ```bash Update read the docs with the latest ``` -------------------------------- ### Use Q Objects for Complex Filtering Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/filtering_ordering.md Demonstrates using Q objects for OR conditions and negation. Q objects can be combined with '&' and '|' operators for complex logical expressions. ```python Q(name__icontains='arabica') | ~Q(name__endswith='blend') ``` -------------------------------- ### Change Connection with Modern API Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/configuration.md Demonstrates how to change the database connection dynamically using the modern configuration API by updating the `database_url` attribute. ```python from neomodel import get_config config = get_config() config.database_url = 'bolt://new:url@localhost:7687' # Using self-managed driver db.set_connection(driver=my_driver) ``` -------------------------------- ### Streamlit Integration with Class Reloading Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/extending.md Demonstrates enabling `ALLOW_RELOAD` in a Streamlit application to handle class redefinitions during hot-reloading. Ensure `DATABASE_URL` is also configured. ```python import streamlit as st from neomodel import StructuredNode, StringProperty, config config.DATABASE_URL = 'bolt://neo4j:neo4j@localhost:7687' config.ALLOW_RELOAD = True # Allows Streamlit page reloads class User(StructuredNode): name = StringProperty(unique_index=True) email = StringProperty() st.write("User model loaded successfully") ``` -------------------------------- ### Set Basic Database URL Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/configuration.md Configure the primary database connection URL for neomodel. This is the recommended approach for neomodel-managed connections. ```python from neomodel import get_config config = get_config() config.database_url = 'bolt://neo4j:password@localhost:7687' ``` -------------------------------- ### Using Collect Aggregation Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/advanced_query_operations.md Demonstrates the use of the Collect aggregation with an optional distinct clause to gather unique related elements. Ensure necessary imports are present. ```python from neomodel.sync_.match import Collect, Last # distinct is optional, and defaults to False. When true, objects are deduplicated Supplier.nodes.traverse_relations(available_species="coffees__species") .annotate(Collect("available_species", distinct=True)) .all() # Last is used to get the last element of a list Supplier.nodes.traverse_relations(available_species="coffees__species") .annotate(Last(Collect("last_species"))) .all() ``` -------------------------------- ### Mixing Impersonation and Transactions Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/transactions.md Demonstrates nesting impersonation with transaction context managers. Both nested transactions will run under the same impersonated user. ```python from neomodel import db @db.impersonate(user="tempuser") # Both transactions will be run as the same impersonated user def func0(): @db.transaction() def func1(): ... @db.transaction() def func2(): ... ``` -------------------------------- ### Commit, Tag, and Push Changes Source: https://github.com/neo4j-contrib/neomodel/wiki/Making-a-release-to-PyPI Commit the version number changes, create a new tag for the release, and push the tag to the remote repository. ```bash $ git commit -a -m " release" $ git tag $ git push --tags ``` -------------------------------- ### Set Advanced Driver Configurations Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/configuration.md Configure advanced driver settings such as connection timeout, pool size, and encryption. These options allow fine-tuning of the Neo4j driver behavior. ```python config.connection_timeout = 60.0 config.max_connection_pool_size = 50 config.encrypted = True config.keep_alive = True ``` -------------------------------- ### Create Node with Point Property (Cypher) Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/spatial_properties.md Use the `point(.)` keyword to create a node with a Point property. The CRS can be specified explicitly. ```default CREATE (a:SomeLabel{location:point({x:0.0,y:0.0})}); ``` ```default CREATE (a:SomeLabel{location:point({x:0,y:0, crs:'cartesian'})}); ``` -------------------------------- ### Configure Aura Test Database Credentials Source: https://github.com/neo4j-contrib/neomodel/blob/master/README.md Set environment variables for Aura test database credentials if the tests fail due to missing connection details. ```bash export AURA_TEST_DB_USER=username ``` ```bash export AURA_TEST_DB_PASSWORD=password ``` ```bash export AURA_TEST_DB_HOSTNAME=url ``` -------------------------------- ### Validate Configuration Values Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/configuration.md Demonstrates neomodel's configuration validation by attempting to set an invalid value for `connection_timeout`. This will raise a `ValueError`. ```python from neomodel import get_config config = get_config() # This will raise a ValueError try: config.connection_timeout = -1 except ValueError as e: print(f"Validation error: {e}") ``` -------------------------------- ### Iterate, Slice, and Count Nodes Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/getting_started.md Demonstrates iteration, slicing, and counting of nodes using neomodel's NodeSet objects. Note that length and boolean checks do not return NodeSet objects and cannot be chained. ```python # Iterable for coffee in Coffee.nodes: print coffee.name # Sliceable using python slice syntax coffee = Coffee.nodes.filter(price__gt=2)[2:] # Count with __len__ print len(Coffee.nodes.filter(price__gt=2)) if Coffee.nodes: print "We have coffee nodes!" ``` -------------------------------- ### Generate Class Diagram with Neomodel Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/getting_started.md Generates a class diagram of your neomodel models. Specify the directory to look for classes and optionally the file type and output directory. Relationship properties are not supported in the diagram. ```bash $ neomodel_generate_diagram models/my_models.py --file-type arrows --write-to-dir img ``` -------------------------------- ### Validate Database URL Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/configuration.md Demonstrates how invalid database URLs are caught by a ValueError during configuration. ```python try: config.database_url = "invalid-url" except ValueError as e: print(f"Validation error: {e}") ``` -------------------------------- ### Manual Explicit Write Transaction Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/transactions.md Manually begin a WRITE transaction using db.begin("WRITE"). This is useful when explicit control over transaction type is needed. ```python db.begin("WRITE") ... db.begin("READ") ... db.begin() # By default a **WRITE** transaction ``` -------------------------------- ### Set Relationship Properties for Multiple Nodes in a Batch Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/batch.md Create multiple nodes in a single batch operation and set common relationship properties using `rel_props`. This is efficient for creating several related entities at once. ```python alice = Person.get_or_create({"name": "Alice"})[0] since_date = datetime(2021, 5, 20, tzinfo=UTC) dogs = Dog.get_or_create( {"name": "Rex"}, {"name": "Max"}, {"name": "Luna"}, relationship=alice.pets, rel_props={"since": since_date, "notes": "Adopted together"}, ) ``` -------------------------------- ### Inspect Neo4j Database to Generate Models Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/getting_started.md Use the `neomodel_inspect_database` command-line tool to automatically generate neomodel Python model definitions from an existing Neo4j database. Specify the database URL and an output file path. ```bash $ neomodel_inspect_database --db bolt://neo4j_username:neo4j_password@localhost:7687 --write-to yourapp/models.py ``` -------------------------------- ### Enable Soft Cardinality Checking Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/configuration.md Activates soft cardinality checking, which generates warnings instead of errors when relationship cardinality constraints are violated. ```python config.soft_cardinality_check = True # default False ``` -------------------------------- ### Basic Path Traversal Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/traversal.md Find all Coffee nodes that have a supplier and retrieve the country of that supplier. This generates a Cypher MATCH clause traversing Coffee<–Supplier–>Country. ```python Coffee.nodes.traverse("suppliers__country").all() ``` -------------------------------- ### Combine Q Objects with AND and OR Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/filtering_ordering.md Filters coffee nodes containing 'arabica' and either a price less than 5 or greater than 10. Chaining Q objects within filter acts as an AND clause. ```python not_middle_priced_arabicas = Coffee.nodes.filter( Q(name__icontains='arabica'), Q(price__lt=5) | Q(price__gt=10) ) ``` -------------------------------- ### Create or Update Node with Relationship Properties Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/batch.md Use the `relationship` and `rel_props` parameters to create or update a node within a specific relationship context and set properties on that relationship. Note that if a node is updated, a new relationship will be created, and old ones will remain. ```python from datetime import datetime, UTC class PetsRel(StructuredRel): since = DateTimeProperty() notes = StringProperty() class Dog(StructuredNode): name = StringProperty(required=True) owner = RelationshipTo('Person', 'OWNS', model=PetsRel) class Person(StructuredNode): name = StringProperty(unique_index=True) pets = RelationshipFrom('Dog', 'OWNS', model=PetsRel) charlie = Person.get_or_create({"name": "Charlie"})[0] since_date = datetime(2019, 3, 10, tzinfo=UTC) dogs = Dog.create_or_update( {"name": "Spot"}, relationship=charlie.pets, rel_props={"since": since_date, "notes": "First adoption"}, ) ``` -------------------------------- ### Enabling Impersonation with Context Manager Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/transactions.md Use the `db.impersonate` context manager to execute database operations as a specific user. This is a Neo4j Enterprise feature. ```python from neomodel import db with db.impersonate(user="writeuser"): Person(name='Bob').save() ``` -------------------------------- ### Conditional Async/Sync Code Execution Source: https://github.com/neo4j-contrib/neomodel/blob/master/README.md Use AsyncUtil.is_async_code to conditionally execute code blocks based on whether the environment is running in async or sync mode. This utility is adapted from the Neo4j Python driver. ```python from neomodel._async_compat.util import AsyncUtil # AsyncUtil.is_async_code is always True if AsyncUtil.is_async_code: # Specific async code # This one gets run when in async mode assert await Coffee.nodes.check_contains(2) else: # Specific sync code # This one gest run when in sync mode assert 2 in Coffee.nodes ``` -------------------------------- ### Implementing Cypher Subqueries Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/advanced_query_operations.md Demonstrates how to embed a Cypher subquery using the subquery method. This allows operations to be performed in isolation, with specified variables returned to the outer query. Requires imports for Collect, Last, and resolvers. ```python from neomodel.sync_match import Collect, Last # This will create a CALL{} subquery # And return a variable named supps usable in the rest of your query Coffee.nodes.filter(name="Espresso") .subquery( Coffee.nodes.traverse_relations(suppliers="suppliers") .intermediate_transform( {"suppliers": {"source": "suppliers"}}, ordering=["suppliers.delivery_cost"] ) .annotate(supps=Last(Collect("suppliers"))), ["supps"], [NodeNameResolver("self")] ) ``` -------------------------------- ### Retrieve Node by Unique Identifier Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/properties.md Demonstrates how to query for a node using its unique identifier generated by UniqueIdProperty. ```python Person.nodes.get(uid='a12df...') ``` -------------------------------- ### Handle Mandatory Property Failure Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/properties.md Demonstrates a scenario where saving an entity fails because a mandatory property ('full_name') is not provided. ```python some_person = Person().save() ``` -------------------------------- ### Batch Create or Update Nodes with Shared Relationship Properties Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/batch.md Efficiently create or update multiple nodes in a single batch operation, all associated with the same relationship and relationship properties. This is useful for adding multiple related entities at once. ```python diana = Person.get_or_create({"name": "Diana"})[0] since_date = datetime(2022, 6, 15, tzinfo=UTC) dogs = Dog.create_or_update( {"name": "Bella"}, {"name": "Charlie"}, {"name": "Daisy"}, relationship=diana.pets, rel_props={"since": since_date, "notes": "Rescue dogs"}, ) ``` -------------------------------- ### Advanced Ordering with Raw Cypher Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/filtering_ordering.md Utilize the `RawCypher` method for advanced ordering, such as ordering by a transformed property. The `$n` placeholder represents the node being ordered. ```python from neomodel.sync_.match import RawCypher class SoftwareDependency(AsyncStructuredNode): name = StringProperty() version = StringProperty() SoftwareDependency(name="Package2", version="1.4.0").save() SoftwareDependency(name="Package3", version="2.5.5").save() latest_dep = SoftwareDependency.nodes.order_by( RawCypher("toInteger(split($n.version, '.')[0]) DESC"), ) ``` -------------------------------- ### Batch Create Nodes Source: https://github.com/neo4j-contrib/neomodel/blob/master/doc/source/batch.md Create multiple nodes at once in a single transaction using the `create()` method. This is a convenience method for compatibility with the Neo4j REST API. ```python with db.transaction: people = Person.create( {'name': 'Tim', 'age': 83}, {'name': 'Bob', 'age': 23}, {'name': 'Jill', 'age': 34}, ) ``` -------------------------------- ### Define Node with No Properties Source: https://github.com/neo4j-contrib/neomodel/blob/master/test/data/neomodel_inspect_database_output.txt Defines a simple neomodel node with no explicit properties. ```python class NoPropertyNode(StructuredNode): pass ```