Django JSONField
django-jsonfield provides a robust JSONField for Django models, offering functionality similar to Django's built-in JSONField (introduced in Django 3.1) but with compatibility for older Django versions (2.2+). It supports direct key lookups and queries on JSON data. The library is actively maintained with releases tied to Django compatibility updates and bug fixes. The current version is 1.4.1.
Common errors
-
ImportError: cannot import name 'JSONField' from 'django_jsonfield.fields'
cause You are trying to import `JSONField` from a non-existent module named `django_jsonfield.fields`. The correct internal package name is `jsonfield`.fixChange your import statement to `from jsonfield.fields import JSONField`. -
TypeError: __init__() got an unexpected keyword argument 'db_index'
cause You are attempting to use the `db_index` parameter with `JSONField` from `django-jsonfield` version 1.0 or newer. This parameter was removed because it was not functionally supported by PostgreSQL for JSONB columns.fixRemove the `db_index` argument from your `JSONField` definition in your Django model (e.g., change `JSONField(db_index=True)` to `JSONField()`).
Warnings
- gotcha Django 3.1 and newer versions include a built-in `JSONField` (`from django.db.models import JSONField`). `django-jsonfield` provides a distinct implementation for older Django versions (2.2-3.0) or specific features. Be careful not to mix them, as behavior and query methods may differ. If using Django 3.1+, consider the built-in field first unless you have a specific reason for this library.
- breaking The `db_index` parameter was removed from `JSONField` in version 1.0. This parameter was never actually supported by PostgreSQL for JSONB columns and was silently ignored. Using it with `django-jsonfield>=1.0` will raise a `TypeError`.
- gotcha The Python package name for the `JSONField` class is `jsonfield`, not `django_jsonfield`. Attempting to import from `django_jsonfield.fields` will result in an `ImportError`.
Install
-
pip install django-jsonfield
Imports
- JSONField
from django_jsonfield.fields import JSONField
from jsonfield.fields import JSONField
- JSONField
from django.db.models import JSONField
from jsonfield.fields import JSONField
Quickstart
import os
import django
from django.conf import settings
from django.db import models
from jsonfield.fields import JSONField # Correct import
# Minimal Django setup for standalone script
if not settings.configured:
settings.configure(
DEBUG=True,
INSTALLED_APPS=[
'myapp', # A dummy app for models
],
DATABASES={
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:',
}
},
)
django.setup()
class MyModel(models.Model):
name = models.CharField(max_length=255)
metadata = JSONField(default=dict) # Use default=dict for easier creation
class Meta:
app_label = 'myapp' # Required when models are not in a formal app dir
def __str__(self):
return f"{self.name} (Metadata: {self.metadata})";
# Simulate migrations for the quickstart
try:
from django.core.management import call_command
from io import StringIO
out = StringIO()
call_command('makemigrations', 'myapp', stdout=out, stderr=out, verbosity=0)
call_command('migrate', 'myapp', stdout=out, stderr=out, verbosity=0)
except Exception as e:
print(f"Warning: Could not run Django migrations simulation: {e}. Attempting manual schema creation.")
# Fallback for environments where call_command is tricky
with django.db.connection.schema_editor() as schema_editor:
schema_editor.create_model(MyModel)
# Create an instance
instance = MyModel.objects.create(
name="Product A",
metadata={'sku': 'P-001', 'dimensions': {'width': 10, 'height': 20}}
)
print(f"Created: {instance}")
# Update JSON data
instance.metadata['status'] = 'available'
instance.metadata['dimensions']['depth'] = 5
instance.save()
print(f"Updated: {instance}")
# Retrieve and access JSON data
retrieved = MyModel.objects.get(name="Product A")
print(f"Retrieved SKU: {retrieved.metadata['sku']}")
# Query JSON data directly (supported by django-jsonfield)
products_with_sku = MyModel.objects.filter(metadata__sku='P-001')
print(f"Found {products_with_sku.count()} product(s) with SKU P-001.")
products_wide = MyModel.objects.filter(metadata__dimensions__width__gt=5)
print(f"Found {products_wide.count()} product(s) with width > 5.")