# How to Integrate neomodel with Django Using django_neomodel: A Complete Guide

> Integrate neomodel with Django using django_neomodel. Learn to configure Neo4j and create graph-aware models for Django-style queries and signals. Get the complete guide.

- Repository: [Neo4j Contrib/neomodel](https://github.com/neo4j-contrib/neomodel)
- Tags: how-to-guide
- Published: 2026-03-08

---

**You can integrate neomodel with Django by installing the django-neomodel package, configuring Neo4j connection settings in your Django settings.py, and inheriting from DjangoNode instead of Django's Model to create graph-aware models that support Django-style queries and signals.**

The neo4j-contrib/neomodel library provides a powerful Object-Graph Mapper (OGM) for Neo4j, but integrating it into a Django project requires a bridge to handle settings, connections, and the familiar ORM API. The django-neomodel package serves as that bridge, allowing you to define StructuredNode models that behave like Django models while leveraging Neo4j's graph capabilities.

## What Is django_neomodel and Why Use It?

django_neomodel acts as a thin architectural bridge between Django's request/response cycle and neomodel's graph-mapping layer. The integration works through three distinct layers:

- **Django**: Manages the traditional request cycle, settings, and deployment workflow.
- **django_neomodel**: Supplies the `DjangoNode` base class, reads Neo4j credentials from [`settings.py`](https://github.com/neo4j-contrib/neomodel/blob/main/settings.py), and registers Django signals (`pre_save`, `post_save`) that map to neomodel hooks.
- **neomodel**: Implements the actual OGM logic, Cypher query building, and transaction handling in [`neomodel/core.py`](https://github.com/neo4j-contrib/neomodel/blob/main/neomodel/core.py) and [`neomodel/match.py`](https://github.com/neo4j-contrib/neomodel/blob/main/neomodel/match.py).

The bridge ensures a singleton `Database` object reuses the driver created by Django, maintaining a single connection pool throughout the process. This design allows you to write Django-style code while neomodel handles the underlying Cypher generation.

## Installation and Configuration

Install both packages using pip. The `extras` flag for neomodel ensures optional dependencies are available:

```bash
pip install neomodel[extras]
pip install django-neomodel

```

Configure your Neo4j connection in [`settings.py`](https://github.com/neo4j-contrib/neomodel/blob/main/settings.py). django_neomodel reads these variables automatically via `django_neomodel.connection.get_connection()`:

```python

# settings.py

NEO4J_BOLT_URL = "bolt://neo4j:password@localhost:7687"
NEO4J_ENCRYPTED = False  # Optional, defaults to True

NEO4J_MAX_CONNECTION_POOL_SIZE = 50  # Optional

```

Add `django_neomodel` to your `INSTALLED_APPS` if you need its management commands or admin integration:

```python
INSTALLED_APPS = [
    # ...

    'django_neomodel',
]

```

## Defining Graph Models with DjangoNode

Instead of inheriting from `django.db.models.Model`, your models inherit from `django_neomodel.models.DjangoNode`. This class extends neomodel's `StructuredNode` (defined in [`neomodel/core.py`](https://github.com/neo4j-contrib/neomodel/blob/main/neomodel/core.py)) to work within Django's ecosystem.

```python

# myapp/models.py

from django_neomodel import DjangoNode
from neomodel import StringProperty, FloatProperty, ArrayProperty, VectorIndex

class Product(DjangoNode):
    """
    A product node stored in Neo4j, accessible via Django's API.
    """
    name = StringProperty()
    description = StringProperty()
    # Semantic index for vector similarity search

    description_embedding = ArrayProperty(
        FloatProperty(), 
        vector_index=VectorIndex(dimensions=2)
    )
    
    class Meta:
        app_label = 'myapp'

```

The `DjangoNode` base class automatically registers the model with Django's app registry while preserving all neomodel functionality, including schema enforcement and relationship definitions.

## Querying Neo4j with Django-Style Syntax

django_neomodel translates Django-style lookups into Cypher queries. You can use familiar double-underscore syntax (`__gt`, `__lte`, `__contains`) alongside neomodel's advanced features like vector similarity filters.

```python

# views.py

from .models import Product
from neomodel.semantic_filters import VectorFilter

# Standard Django lookup translated to Cypher WHERE clause

expensive_products = Product.nodes.filter(price__gt=100).all()

# Combine vector similarity with Django numeric filters

# This demonstrates the seamless API integration tested in test/sync_/test_vectorfilter.py

similar_products = Product.nodes.filter(
    vector_filter=VectorFilter(
        topk=5,
        vector_attribute_name="description_embedding",
        candidate_vector=[0.12, 0.34],
    ),
    price__lte=200,
).all()

```

As implemented in [`neomodel/semantic_filters.py`](https://github.com/neo4j-contrib/neomodel/blob/main/neomodel/semantic_filters.py), the `VectorFilter` class constructs the appropriate Cypher for vector index queries, while the standard lookups are handled by neomodel's query builder in [`neomodel/match.py`](https://github.com/neo4j-contrib/neomodel/blob/main/neomodel/match.py). The test file [`test/sync_/test_vectorfilter.py`](https://github.com/neo4j-contrib/neomodel/blob/main/test/sync_/test_vectorfilter.py) (lines 91-100) demonstrates this exact pattern of mixing vector filters with Django-style numeric lookups.

## Leveraging Django Signals and Hooks

One of the primary benefits of django_neomodel is the automatic wiring of Django's signal system to neomodel's lifecycle hooks. As documented in `doc/source/hooks.rst`, you can use standard Django signals while operating on graph data.

```python

# signals.py

from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Product
import logging

logger = logging.getLogger(__name__)

@receiver(post_save, sender=Product)
def product_saved_handler(sender, instance, **kwargs):
    """
    Executed after a Product node is persisted to Neo4j.
    The django_neomodel bridge ensures this fires correctly.
    """
    logger.info(f"Product {instance.name} saved to Neo4j graph")

```

The `django_neomodel` module registers these signal handlers internally, mapping `pre_save` and `post_save` to neomodel's native hooks. This allows you to reuse existing Django signal logic without modification when switching from a relational database to Neo4j.

## Key Source Files and Implementation Details

Understanding the integration architecture requires examining specific files in the neo4j-contrib/neomodel repository:

- **[`neomodel/properties.py`](https://github.com/neo4j-contrib/neomodel/blob/main/neomodel/properties.py)**: Defines property classes like `StringProperty` and `ArrayProperty` with optional `label` and `help_text` arguments consumed by `django_neomodel` for form generation.

- **`doc/source/index.rst`**: Documents the Django integration and links to the external `django_neomodel` repository, confirming the supported integration pattern.

- **`doc/source/hooks.rst`**: Explicitly states that Django signals are supported via the `django_neomodel` module, detailing the signal registration mechanism.

- **[`test/sync_/test_vectorfilter.py`](https://github.com/neo4j-contrib/neomodel/blob/main/test/sync_/test_vectorfilter.py)** (lines 91-100): Contains the test case `test_django_filter_w_vector_filter` demonstrating the combination of `VectorFilter` with Django-style numeric lookups like `number__gt=5`.

- **[`neomodel/semantic_filters.py`](https://github.com/neo4j-contrib/neomodel/blob/main/neomodel/semantic_filters.py)**: Implements the `VectorFilter` class used for semantic similarity queries within Django-style filter calls.

These files demonstrate how neomodel is designed to be consumed by external frameworks, with `django_neomodel` acting as the official bridge for Django projects.

## Summary

- **django_neomodel** bridges Django's ecosystem with neomodel's graph mapping, allowing you to use Django settings, signals, and query syntax with Neo4j.
- Configure the integration by setting `NEO4J_BOLT_URL` and other variables in [`settings.py`](https://github.com/neo4j-contrib/neomodel/blob/main/settings.py), which `django_neomodel.connection.get_connection()` reads automatically.
- Inherit from `DjangoNode` instead of Django's `Model` to create graph-aware classes that support both neomodel properties and Django's app registry.
- Query using Django-style lookups (`__gt`, `__lte`) alongside advanced neomodel features like `VectorFilter` for semantic search, as demonstrated in [`test/sync_/test_vectorfilter.py`](https://github.com/neo4j-contrib/neomodel/blob/main/test/sync_/test_vectorfilter.py).
- Leverage existing Django signals (`pre_save`, `post_save`) without modification, as the bridge automatically wires them to neomodel's lifecycle hooks according to `doc/source/hooks.rst`.

## Frequently Asked Questions

### What is the difference between neomodel and django_neomodel?

**neomodel** is the core Object-Graph Mapper for Neo4j that provides the `StructuredNode` base class, property definitions, and Cypher query building. **django_neomodel** is a separate package that acts as a bridge, providing the `DjangoNode` base class, reading Django settings for Neo4j connections, and registering Django signals with neomodel hooks. You need both packages to use Neo4j within a Django project while maintaining Django's familiar patterns.

### Can I use Django's admin interface with neomodel models?

**Yes**, but with limitations. Because `DjangoNode` inherits from neomodel's `StructuredNode` rather than Django's `Model`, it does not automatically integrate with Django's built-in admin interface for relational databases. However, you can create custom admin views or use third-party packages that bridge neomodel with Django admin. The `label` and `help_text` arguments in [`neomodel/properties.py`](https://github.com/neo4j-contrib/neomodel/blob/main/neomodel/properties.py) are specifically designed to support form generation when such integrations are built.

### How do I handle migrations with django_neomodel?

**django_neomodel does not use Django's migration system** because Neo4j is schema-optional and neomodel handles schema enforcement through its own `install_labels` and `install_all_labels` utilities. Instead of running `makemigrations` and `migrate`, you use neomodel's built-in commands to create indexes and constraints in Neo4j. The connection settings in [`settings.py`](https://github.com/neo4j-contrib/neomodel/blob/main/settings.py) are read by `django_neomodel.connection.get_connection()`, but database schema changes are managed through neomodel's native OGM methods rather than Django's relational migration framework.

### Is it possible to use both Django ORM and neomodel in the same project?

**Yes**, this is a common pattern for polyglot persistence. You can use Django's standard ORM for relational data (PostgreSQL, MySQL, etc.) while using `django_neomodel` for graph data in Neo4j. Simply define traditional models inheriting from `django.db.models.Model` alongside graph models inheriting from `django_neomodel.DjangoNode`. The two systems operate independently, allowing you to store user sessions and transactional data in SQL while keeping complex relationship data in Neo4j, leveraging the strengths of each database within the same Django project.