diff --git a/.circleci/config.yml b/.circleci/config.yml
index 8e7a6f5..75a342a 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -3,7 +3,7 @@ jobs:
test-python36:
docker:
- image: python:3.6-alpine
- - image: postgres:11.0
+ - image: postgres:12.0
environment:
POSTGRES_DB: 'localizedfields'
POSTGRES_USER: 'localizedfields'
@@ -11,26 +11,25 @@ jobs:
steps:
- checkout
- run:
- name: Install packages
- command: apk add postgresql-libs gcc musl-dev postgresql-dev git
+ name: Install packages
+ command: apk add postgresql-libs gcc musl-dev postgresql-dev git
- run:
- name: Install Python packages
- command: pip install --progress-bar off .[test]
+ name: Install Python packages
+ command: pip install --progress-bar off .[test]
- run:
- name: Run tests
- command: tox -e 'py36-dj{20,21,22,30,31}'
- environment:
- DATABASE_URL: 'postgres://localizedfields:localizedfields@localhost:5432/localizedfields'
+ name: Run tests
+ command: tox -e 'py36-dj{20,21,22,30,31,32}'
+ environment:
+ DATABASE_URL: 'postgres://localizedfields:localizedfields@localhost:5432/localizedfields'
- store_test_results:
- path: reports
-
+ path: reports
test-python37:
docker:
- image: python:3.7-alpine
- - image: postgres:11.0
+ - image: postgres:12.0
environment:
POSTGRES_DB: 'localizedfields'
POSTGRES_USER: 'localizedfields'
@@ -38,26 +37,25 @@ jobs:
steps:
- checkout
- run:
- name: Install packages
- command: apk add postgresql-libs gcc musl-dev postgresql-dev git
+ name: Install packages
+ command: apk add postgresql-libs gcc musl-dev postgresql-dev git
- run:
- name: Install Python packages
- command: pip install --progress-bar off .[test]
+ name: Install Python packages
+ command: pip install --progress-bar off .[test]
- run:
- name: Run tests
- command: tox -e 'py37-dj{20,21,22,30,31}'
- environment:
- DATABASE_URL: 'postgres://localizedfields:localizedfields@localhost:5432/localizedfields'
+ name: Run tests
+ command: tox -e 'py37-dj{20,21,22,30,31,32}'
+ environment:
+ DATABASE_URL: 'postgres://localizedfields:localizedfields@localhost:5432/localizedfields'
- store_test_results:
- path: reports
-
+ path: reports
test-python38:
docker:
- image: python:3.8-alpine
- - image: postgres:11.0
+ - image: postgres:12.0
environment:
POSTGRES_DB: 'localizedfields'
POSTGRES_USER: 'localizedfields'
@@ -74,7 +72,7 @@ jobs:
- run:
name: Run tests
- command: tox -e 'py38-dj{20,21,22,30,31}'
+ command: tox -e 'py38-dj{20,21,22,30,31,32,40,41,42}'
environment:
DATABASE_URL: 'postgres://localizedfields:localizedfields@localhost:5432/localizedfields'
@@ -84,7 +82,7 @@ jobs:
test-python39:
docker:
- image: python:3.9-alpine
- - image: postgres:11.0
+ - image: postgres:12.0
environment:
POSTGRES_DB: 'localizedfields'
POSTGRES_USER: 'localizedfields'
@@ -101,16 +99,69 @@ jobs:
- run:
name: Run tests
- command: tox -e 'py39-dj{21,22,30,31}'
+ command: tox -e 'py39-dj{30,31,32,40,41,42}'
environment:
DATABASE_URL: 'postgres://localizedfields:localizedfields@localhost:5432/localizedfields'
- store_test_results:
path: reports
+ test-python310:
+ docker:
+ - image: python:3.10-alpine
+ - image: postgres:12.0
+ environment:
+ POSTGRES_DB: 'localizedfields'
+ POSTGRES_USER: 'localizedfields'
+ POSTGRES_PASSWORD: 'localizedfields'
+ steps:
+ - checkout
+ - run:
+ name: Install packages
+ command: apk add postgresql-libs gcc musl-dev postgresql-dev git
+
+ - run:
+ name: Install Python packages
+ command: pip install --progress-bar off .[test]
+
+ - run:
+ name: Run tests
+ command: tox -e 'py310-dj{32,40,41,42,50}'
+ environment:
+ DATABASE_URL: 'postgres://localizedfields:localizedfields@localhost:5432/localizedfields'
+
+ - store_test_results:
+ path: reports
+ test-python311:
+ docker:
+ - image: python:3.11-alpine
+ - image: postgres:12.0
+ environment:
+ POSTGRES_DB: 'localizedfields'
+ POSTGRES_USER: 'localizedfields'
+ POSTGRES_PASSWORD: 'localizedfields'
+ steps:
+ - checkout
+ - run:
+ name: Install packages
+ command: apk add postgresql-libs gcc musl-dev postgresql-dev git
+
+ - run:
+ name: Install Python packages
+ command: pip install --progress-bar off .[test]
+
+ - run:
+ name: Run tests
+ command: tox -e 'py311-dj{42,50}'
+ environment:
+ DATABASE_URL: 'postgres://localizedfields:localizedfields@localhost:5432/localizedfields'
+
+ - store_test_results:
+ path: reports
+
analysis:
docker:
- - image: python:3.7-alpine
+ - image: python:3.8-alpine
steps:
- checkout
- run:
@@ -134,4 +185,6 @@ workflows:
- test-python37
- test-python38
- test-python39
+ - test-python310
+ - test-python311
- analysis
diff --git a/README.md b/README.md
index adc20c3..49a9d19 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,13 @@
-| | | |
-|--------------------|---------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| | | |
+|--------------------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| :white_check_mark: | **Tests** | [![CircleCI](https://circleci.com/gh/SectorLabs/django-localized-fields/tree/master.svg?style=svg)](https://circleci.com/gh/SectorLabs/django-localized-fields/tree/master) |
-| :memo: | **License** | [![License](https://img.shields.io/:license-mit-blue.svg)](http://doge.mit-license.org) |
-| :package: | **PyPi** | [![PyPi](https://badge.fury.io/py/django-localized-fields.svg)](https://pypi.python.org/pypi/django-localized-fields) |
-| | **Django Versions** | 2.0, 2.1, 2.2, 3.0, 3.1, 3.2 |
-| | **Python Versions** | 3.6, 3.7, 3.8, 3.9 |
-| :book: | **Documentation** | [Read The Docs](https://django-localized-fields.readthedocs.io) |
-| :warning: | **Upgrade** | [Upgrade fom v5.x](https://django-localized-fields.readthedocs.io/en/latest/releases.html#v6-0)
-| :checkered_flag: | **Installation** | [Installation Guide](https://django-localized-fields.readthedocs.io/en/latest/installation.html) |
+| :memo: | **License** | [![License](https://img.shields.io/:license-mit-blue.svg)](http://doge.mit-license.org) |
+| :package: | **PyPi** | [![PyPi](https://badge.fury.io/py/django-localized-fields.svg)](https://pypi.python.org/pypi/django-localized-fields) |
+| | **Django Versions** | 2.0, 2.1, 2.2, 3.0, 3.1, 3.2, 4.0, 4.1, 4.2, 5.0 |
+| | **Python Versions** | 3.6, 3.7, 3.8, 3.9, 3.10, 3.11 |
+| :book: | **Documentation** | [Read The Docs](https://django-localized-fields.readthedocs.io) |
+| :warning: | **Upgrade** | [Upgrade fom v5.x](https://django-localized-fields.readthedocs.io/en/latest/releases.html#v6-0)
+| :checkered_flag: | **Installation** | [Installation Guide](https://django-localized-fields.readthedocs.io/en/latest/installation.html) |
`django-localized-fields` is an implementation of a field class for Django models that allows the field's value to be set in multiple languages. It does this by utilizing the ``hstore`` type (PostgreSQL specific), which is available as `models.HStoreField` since Django 1.10.
@@ -20,7 +20,7 @@
## Working with the code
### Prerequisites
-* PostgreSQL 10 or newer.
+* PostgreSQL 12 or newer.
* Django 2.0 or newer.
* Python 3.6 or newer.
diff --git a/localized_fields/lookups.py b/localized_fields/lookups.py
index 1536450..ba38980 100644
--- a/localized_fields/lookups.py
+++ b/localized_fields/lookups.py
@@ -43,6 +43,10 @@ def process_lhs(self, qn, connection):
return super().process_lhs(qn, connection)
def get_prep_lookup(self):
+ # Django 4.0 removed the ability for isnull fields to be something other than a bool
+ # We should NOT convert them to strings
+ if isinstance(self.rhs, bool):
+ return self.rhs
return str(self.rhs)
diff --git a/setup.py b/setup.py
index 52d8292..b076389 100644
--- a/setup.py
+++ b/setup.py
@@ -36,7 +36,7 @@ def run(self):
setup(
name="django-localized-fields",
- version="6.8b3",
+ version="6.8b4",
packages=find_packages(exclude=["tests"]),
include_package_data=True,
license="MIT License",
@@ -67,6 +67,8 @@ def run(self):
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
"Topic :: Internet :: WWW/HTTP",
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
],
@@ -80,14 +82,14 @@ def run(self):
':python_version <= "3.6"': ["dataclasses"],
"docs": ["Sphinx==2.2.0", "sphinx-rtd-theme==0.4.3"],
"test": [
- "tox==3.14.3",
- "pytest==5.3.2",
- "pytest-django==3.7.0",
- "pytest-cov==2.8.1",
+ "tox==3.28.0",
+ "pytest==7.0.1",
+ "pytest-django==4.5.2",
+ "pytest-cov==2.12.1",
"dj-database-url==0.5.0",
- "django-autoslug==1.9.6",
- "django-bleach==0.6.1",
- "psycopg2==2.8.4",
+ "django-autoslug==1.9.9",
+ "django-bleach==0.9.0",
+ "psycopg2==2.9.8",
],
"analysis": [
"black==22.3.0",
diff --git a/tests/test_isnull.py b/tests/test_isnull.py
new file mode 100644
index 0000000..fb54e52
--- /dev/null
+++ b/tests/test_isnull.py
@@ -0,0 +1,51 @@
+import django
+import pytest
+
+from django.test import TestCase
+
+from localized_fields.fields import LocalizedField
+from localized_fields.value import LocalizedValue
+
+from .fake_model import get_fake_model
+
+
+class LocalizedIsNullLookupsTestCase(TestCase):
+ """Tests whether ref lookups properly work with."""
+
+ TestModel1 = None
+
+ @classmethod
+ def setUpClass(cls):
+ """Creates the test model in the database."""
+ super(LocalizedIsNullLookupsTestCase, cls).setUpClass()
+ cls.TestModel = get_fake_model(
+ {"text": LocalizedField(null=True, required=[])}
+ )
+ cls.TestModel.objects.create(
+ text=LocalizedValue(dict(en="text_en", ro="text_ro", nl="text_nl"))
+ )
+ cls.TestModel.objects.create(
+ text=None,
+ )
+
+ def test_isnull_lookup_valid_values(self):
+ """Test whether isnull properly works with valid values."""
+ assert self.TestModel.objects.filter(text__isnull=True).exists()
+ assert self.TestModel.objects.filter(text__isnull=False).exists()
+
+ def test_isnull_lookup_null(self):
+ """Test whether isnull crashes with None as value."""
+
+ with pytest.raises(ValueError):
+ assert self.TestModel.objects.filter(text__isnull=None).exists()
+
+ def test_isnull_lookup_string(self):
+ """Test whether isnull properly works with string values on the
+ corresponding Django version."""
+ if django.VERSION < (4, 0):
+ assert self.TestModel.objects.filter(text__isnull="True").exists()
+ else:
+ with pytest.raises(ValueError):
+ assert self.TestModel.objects.filter(
+ text__isnull="True"
+ ).exists()
diff --git a/tox.ini b/tox.ini
index 15dfab6..d931abe 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py36-dj{20,21,22,30,31}, py37-dj{20,21,22,30,31}, py38-dj{20,21,22,30,31}, py39-dj{21,22,30,31}
+envlist = py36-dj{20,21,22,30,31,32}, py37-dj{20,21,22,30,31,32}, py38-dj{20,21,22,30,31,32,40,41,42}, py39-dj{30,31,32,40,41,42}, py310-dj{32,40,41,42,50}, py311-dj{42,50}
[testenv]
deps =
@@ -8,6 +8,11 @@ deps =
dj22: Django>=2.2,<2.3
dj30: Django>=3.0,<3.0.2
dj31: Django>=3.1,<3.2
+ dj32: Django>=3.2,<4.0
+ dj40: Django>=4.0,<4.1
+ dj41: Django>=4.1,<4.2
+ dj42: Django>=4.2,<5.0
+ dj50: Django>=5.0,<5.1
.[test]
setenv =
DJANGO_SETTINGS_MODULE=settings