diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index ea37eef..13a47f0 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -5,7 +5,7 @@ name: Integration tests on: push: - branches: [ "master", "rc/**" ] + branches: [ "rc/**" ] pull_request: branches: [ "master", "rc/**" ] @@ -15,7 +15,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.11", "3.10", "3.9", "3.8", "3.7"] + python-version: ["3.12", "3.11", "3.10", "3.9", "3.8"] neo4j-version: ["community", "4.4-community"] steps: diff --git a/Changelog b/Changelog index 8cb1b40..7438f09 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,7 @@ +Version 0.2.0 2024-05 +* Bump neomodel to 5.3.0 +* Bump Django to 4.2.8 LTS + Version 0.1.1 2023-08 * Bump neomodel to 5.1.0 - full support of Neo4j version 5.x (and 4.4 LTS) * Support higher versions of Django (> 2.2) diff --git a/MANIFEST.in b/MANIFEST.in index 2d767e7..07baa71 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,4 @@ -include README.rst +include README.md include AUTHORS.txt include Changelog include LICENSE diff --git a/README.rst b/README.md similarity index 75% rename from README.rst rename to README.md index 4ea39d3..aada41b 100644 --- a/README.rst +++ b/README.md @@ -1,32 +1,25 @@ -Django Neomodel (beta!) -======================= +# Django Neomodel (beta!) -.. image:: https://raw.githubusercontent.com/robinedwards/neomodel/master/doc/source/_static/neomodel-300.png - :alt: neomodel +![neomodel](https://raw.githubusercontent.com/neo4j-contrib/neomodel/master/doc/source/_static/neomodel-300.png) -This module allows you to use the neo4j_ graph database with Django using neomodel_ +This module allows you to use the [neo4j](https://www.neo4j.org) graph database with Django using [neomodel](http://neomodel.readthedocs.org) -.. _neo4j: https://www.neo4j.org -.. _neomodel: http://neomodel.readthedocs.org -Warnings -======================= +## Warnings -* Admin functionality is very experimental. `Please see todos / issues here `_ +* Admin functionality is very experimental. [Please see todos / issues here](https://github.com/neo4j-contrib/django-neomodel/projects/1) -Live Examples (add yours here) -=============================== +## Live Examples (add yours here) -* `ResoTrack `_ +* [Syracuse](https://syracuse.1145.am>): a database of company linkages created from unstructured text. Repo at [syracuse-neo](https://github.com/alanbuxton/syracuse-neo.git) -Getting started -=============== +# Getting started -Install the module:: +Install the module: $ pip install django_neomodel -Add the following settings to your `settings.py`:: +Add the following settings to your `settings.py`: NEOMODEL_NEO4J_BOLT_URL = os.environ.get('NEO4J_BOLT_URL', 'bolt://neo4j:foobarbaz@localhost:7687') @@ -37,7 +30,7 @@ Add the following settings to your `settings.py`:: 'yourapp' ) -Write your first node definition in `yourapp/models.py`:: +Write your first node definition in `yourapp/models.py`: from neomodel import StructuredNode, StringProperty, DateProperty @@ -46,18 +39,18 @@ Write your first node definition in `yourapp/models.py`:: published = DateProperty() Create any constraints or indexes for your labels. This needs to be done after you change your node definitions -much like `manage.py migrate`:: +much like `manage.py migrate`: $ python manage.py install_labels -Now in a view `yourapp/views.py`:: +Now in a view `yourapp/views.py`: from .models import Book def get_books(request): return render('yourapp/books.html', request, {'books': Book.nodes.all()}) -In your `yourapp/admin.py`:: +In your `yourapp/admin.py`: from django_neomodel import admin as neo_admin from .models import Book @@ -68,10 +61,9 @@ In your `yourapp/admin.py`:: And you're ready to go. Don't forget to check the neomodel_ documentation. -Model forms -=========== +## Model forms -Switch the base class from `StructuredNode` to `DjangoNode` and add a 'Meta' class:: +Switch the base class from `StructuredNode` to `DjangoNode` and add a 'Meta' class: from datetime import datetime from django_neomodel import DjangoNode @@ -90,7 +82,7 @@ Switch the base class from `StructuredNode` to `DjangoNode` and add a 'Meta' cla class Meta: app_label = 'library' -Create a model form class for your `DjangoNode`:: +Create a model form class for your `DjangoNode`: class BookForm(ModelForm): class Meta: @@ -99,19 +91,17 @@ Create a model form class for your `DjangoNode`:: This class may now be used just like any other Django form. -Settings -======== +## Settings The following config options are available in django settings (default values shown). -These are mapped to neomodel.config as django is started:: +These are mapped to neomodel.config as django is started: NEOMODEL_NEO4J_BOLT_URL = 'bolt://neo4j:neo4j@localhost:7687' NEOMODEL_SIGNALS = True NEOMODEL_FORCE_TIMEZONE = False NEOMODEL_MAX_CONNECTION_POOL_SIZE = 50 -Signals -======= -Signals work with `DjangoNode` sub-classes:: +## Signals +Signals work with `DjangoNode` sub-classes: from django.db.models import signals from django_neomodel import DjangoNode @@ -128,10 +118,9 @@ Signals work with `DjangoNode` sub-classes:: The following are supported: `pre_save`, `post_save`, `pre_delete`, `post_delete`. On freshly created nodes `created=True` in the `post_save` signal argument. -Testing -======= +## Testing -You can create a setup method which clears the database before executing each test:: +You can create a setup method which clears the database before executing each test: from neomodel import db, clear_neo4j_database @@ -142,14 +131,12 @@ You can create a setup method which clears the database before executing each te def test_something(self): pass -Management Commands -=================== +## Management Commands The following django management commands have been included. -install_labels --------------- -Setup constraints and indexes on labels for your node definitions. This should be executed after any schema changes:: +### install_labels +Setup constraints and indexes on labels for your node definitions. This should be executed after any schema changes: $ python manage.py install_labels Setting up labels and constraints... @@ -158,27 +145,19 @@ Setup constraints and indexes on labels for your node definitions. This should b + Creating unique constraint for title on label Book for class tests.someapp.models.Book Finished 1 class(es). -clear_neo4j ------------ +### clear_neo4j Delete all nodes in your database, warning there is no confirmation! -Requirements -============ +## Requirements -- Python 3.7+ +- Python 3.8+ - neo4j 5.x, 4.4 (LTS) -.. image:: https://badges.gitter.im/Join%20Chat.svg - :alt: Join the chat at https://gitter.im/robinedwards/neomodel - :target: https://gitter.im/robinedwards/neomodel?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge - -Docker Example -=================== - +## Docker Example Using Docker Compose. -Commands to setup Docker Container docker-entrypoint.sh:: +Commands to setup Docker Container docker-entrypoint.sh: # Go to tests $ cd tests/ @@ -191,12 +170,11 @@ Go to http://localhost:7474/browser/ Go to http://localhost:8000/admin/ -Running Tests -=================== +## Running Tests Setup Neo4j Desktop with a local database with password 'foobarbaz' and version 5.x or 4.4.x (Neo4j LTS version). -Commands to run tests:: +Commands to run tests: # create local venv and install dependencies. $ pip install -e '.[dev]'; export DJANGO_SETTINGS_MODULE=tests.settings; diff --git a/django_neomodel/__init__.py b/django_neomodel/__init__.py index f0ed690..81b3252 100644 --- a/django_neomodel/__init__.py +++ b/django_neomodel/__init__.py @@ -8,15 +8,15 @@ from django.core.exceptions import ValidationError from neomodel import RequiredProperty, DeflateError, StructuredNode, UniqueIdProperty -from neomodel.core import NodeMeta -from neomodel.match import NodeSet +from neomodel.sync_.core import NodeMeta +from neomodel.sync_.match import NodeSet __author__ = "Robin Edwards" __email__ = "robin.ge@gmail.com" __license__ = "MIT" __package__ = "django_neomodel" -__version__ = "0.1.1" +__version__ = "0.2.0" default_app_config = "django_neomodel.apps.NeomodelConfig" diff --git a/django_neomodel/apps.py b/django_neomodel/apps.py index 0808bfc..8c90959 100644 --- a/django_neomodel/apps.py +++ b/django_neomodel/apps.py @@ -3,17 +3,20 @@ from neomodel import config -config.AUTO_INSTALL_LABELS = False - - class NeomodelConfig(AppConfig): - name = 'django_neomodel' - verbose_name = 'Django neomodel' + name = "django_neomodel" + verbose_name = "Django neomodel" def read_settings(self): - config.DATABASE_URL = getattr(settings, 'NEOMODEL_NEO4J_BOLT_URL', config.DATABASE_URL) - config.FORCE_TIMEZONE = getattr(settings, 'NEOMODEL_FORCE_TIMEZONE', False) - config.MAX_CONNECTION_POOL_SIZE = getattr(settings, 'NEOMODEL_MAX_CONNECTION_POOL_SIZE', config.MAX_CONNECTION_POOL_SIZE) + config.DATABASE_URL = getattr( + settings, "NEOMODEL_NEO4J_BOLT_URL", config.DATABASE_URL + ) + config.FORCE_TIMEZONE = getattr(settings, "NEOMODEL_FORCE_TIMEZONE", False) + config.MAX_CONNECTION_POOL_SIZE = getattr( + settings, + "NEOMODEL_MAX_CONNECTION_POOL_SIZE", + config.MAX_CONNECTION_POOL_SIZE, + ) def ready(self): self.read_settings() diff --git a/pyproject.toml b/pyproject.toml index 980589c..284a211 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,19 +9,13 @@ where = ["./"] [project] name = "django_neomodel" -authors = [ - {name = "Robin Edwards", email = "robin.ge@gmail.com"}, -] -maintainers = [ - {name = "Athanasios Anastasiou", email = "athanastasiou@gmail.com"}, - {name = "Cristina Escalante"}, - {name = "Marius Conjeaud", email = "marius.conjeaud@outlook.com"}, -] +authors = [{name = "Robin Edwards", email = "robin.ge@gmail.com"}] +maintainers = [{name = "Marius Conjeaud", email = "marius.conjeaud@outlook.com"}] description = "Use Neo4j with Django!" -readme = "README.rst" -requires-python = ">=3.7" +readme = "README.md" +requires-python = ">=3.8" keywords = ["graph", "neo4j", "django", "plugin", "neomodel"] -license = {text = "MIT"} +license = { text = "MIT" } classifiers = [ "Development Status :: 4 - Beta", 'Intended Audience :: Developers', @@ -33,10 +27,10 @@ classifiers = [ "Topic :: Database", ] dependencies = [ - "neomodel~=5.1.0", - 'django>=2.2' + "neomodel~=5.3.0", + 'django>=4.2.8' ] -version='0.1.1' +version='0.2.0' [project.urls] repository = "http://github.com/robinedwards/django-neomodel" @@ -44,7 +38,7 @@ repository = "http://github.com/robinedwards/django-neomodel" [project.optional-dependencies] dev = [ "pytest>=7.1", - "pytest-django>=3.10.0", + "pytest-django>=4.5.2", "pytest-cov>=4.0", ] diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..0a3a5a6 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,3 @@ +pytest>=7.1 +pytest-django>=4.5.2 +pytest-cov>=4.0 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..c6697d7 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +neomodel~=5.3.0 +django~=4.2.8 \ No newline at end of file diff --git a/test.db b/test.db index d30f22d..88203bc 100644 Binary files a/test.db and b/test.db differ diff --git a/tests/Dockerfile b/tests/Dockerfile index c3ce790..1c9d654 100644 --- a/tests/Dockerfile +++ b/tests/Dockerfile @@ -1,6 +1,6 @@ FROM python:3 WORKDIR /usr/src/app -RUN pip install -e '.[dev]' COPY .. . +RUN pip install -e '.[dev]' RUN chmod +x ./tests/docker-entrypoint.sh CMD ["./tests/docker-entrypoint.sh" ] diff --git a/tests/settings.py b/tests/settings.py index 94d2773..1fed17d 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -9,31 +9,33 @@ DEBUG = True -ROOT_URLCONF = 'tests.urls' -SECRET_KEY = 'skskqlqlaskdsd' +ROOT_URLCONF = "tests.urls" +SECRET_KEY = "skskqlqlaskdsd" AUTOCOMMIT = True DATABASES = { - 'default': { - 'NAME': 'test.db', - 'ENGINE': 'django.db.backends.sqlite3', - 'USER': '', - 'PASSWORD': '', - 'PORT': '', + "default": { + "NAME": "test.db", + "ENGINE": "django.db.backends.sqlite3", + "USER": "", + "PASSWORD": "", + "PORT": "", }, } -NEOMODEL_NEO4J_BOLT_URL = os.environ.get('NEO4J_BOLT_URL', 'bolt://neo4j:foobarbaz@localhost:7687') +NEOMODEL_NEO4J_BOLT_URL = os.environ.get( + "NEO4J_BOLT_URL", "bolt://neo4j:foobarbaz@localhost:7687" +) NEOMODEL_SIGNALS = True NEOMODEL_FORCE_TIMEZONE = False NEOMODEL_MAX_CONNECTION_POOL_SIZE = 50 TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'APP_DIRS': True, + "BACKEND": "django.template.backends.django.DjangoTemplates", + "APP_DIRS": True, "OPTIONS": { "context_processors": [ "django.template.context_processors.debug", @@ -47,23 +49,21 @@ INSTALLED_APPS = [ # Django - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.sites', - 'django.contrib.staticfiles', - + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.sites", + "django.contrib.staticfiles", # Third party - 'django_neomodel', - + "django_neomodel", # Test - 'tests.someapp', + "tests.someapp", ] USE_TZ = True -TIME_ZONE = 'UTC' +TIME_ZONE = "UTC" MIDDLEWARE = [ "django.contrib.sessions.middleware.SessionMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", @@ -71,5 +71,6 @@ ] STATIC_ROOT = "./static/" -STATIC_URL = '/static/' +STATIC_URL = "/static/" +DEFAULT_AUTO_FIELD = "django.db.models.AutoField"